Семинары по курсу «Архитектура ЭВМ и язык ассемблера» учебно-методическое пособие. Часть 1. - Е.А. Кузьменкова_ В.С. Махнычев_ В.А. Падарян (1110587), страница 2
Текст из файла (страница 2)
60Условная передача данных ......................................................................................... 62Задачи ............................................................................................................................ 63Ответы и решения ............................................................................................................ 684Литература ........................................................................................................................ 765ВведениеПособие содержит кратко изложенный материал семинарских занятий по курсу«Архитектура ЭВМ и язык ассемблера», читаемого для студентов 1 потока 1 курсафакультета ВМК МГУ. Рассматриваются темы занятий первой половины семестра,такие как: организация ассемблерной программы, работа с целочисленнымитипами данных и указателями, условная и безусловная передача управления.Основной целью семинарских занятий является практическое знакомство смеханизмами реализации программ, написанных на языке Си.Каждая рассматриваемая тема содержит краткий вводный материал, детальноразобранные типовые задачи и задачи для самостоятельной работы, часть которыхснабжена ответами.Методическое пособие предназначено для преподавателей, ведущихпрактические занятия в поддержку лекционного курса «Архитектура ЭВМ и языкассемблера» для студентов 1 курса, а также рекомендуется студентам приподготовке к письменному экзамену.В настоящем издании существенно переработаны и дополнены разделы пособия,посвященные описанию операций над битовыми векторами и управляющихконструкций языка, а также расширен набор предлагаемых примеров и задач.61.Организация ассемблерной программыПользовательская (прикладная) программа, написанная для платформ IA-32/Linuxили IA-32/Windows, рассчитана на выполнение в машине, реализующей принципыфон Неймана (Рис.
1). Машинные команды и данные хранятся совместно воперативной памяти, а процессор в автоматическом режиме последовательночитает из памяти команды и исполняет их. Оперативная память разбита на ячейкиразмером по 8 двоичных разрядов (1 байт), ячейки пронумерованы числами от 0до 232-1 (номер ячейки называют ее адресом). Процессор содержит набор 32-хразрядных регистров, состоящий из восьми регистров общего назначения, счетчикакоманд, регистра состояния.
Взаимодействие процессором с оперативной памятьюосуществляется через шину, позволяющей процессору считывать значения ячеекоперативной памяти, записывать в ячейки новые значения.Рисунок 1 - Упрощенная схема виртуальной машины IA-32, используемойприкладной программой.Программа, которая готова к исполнению процессором, представляет собойопределенный набор значений ячеек оперативной памяти. Эти значения заносит воперативную память загрузчик — компонент операционной системы, отвечающийза загрузку исполняемого файла (копирование его содержимого) в память. Дляформирования исполняемого файла используются инструменты системыпрограммирования; основными инструментами являются компилятор, ассемблер,компоновщик (Рис. 2).Машина IA-32 позволяет обращаться к произвольному месту оперативной памяти,однако не все ячейки доступны, обращения к одним адресам завершатся успешно,к другим – приведут к аварийной остановке программы.
Причиной является то, чтопользовательская программа работает в защищенном режиме процессора:фактически ей доступны только определенные диапазоны адресов, содержащие7образ программы в памяти. Управление памятью, доступной пользовательскойпрограмме, осуществляет операционная система, этот вопрос выходит за рамкиданного курса.Рисунок 2 - Упрощенная схема компиляции и выполнения прикладной программы.Язык ассемблера позволяет программисту описывать содержимое ячеекоперативной памяти не в виде двоичных чисел, а в виде более удобных длячеловека конструкций и мнемонических обозначений.
Программа на языкеассемблера представляет собой текстовый файл. Программист определяет в этомтекстовом файле набор секций. В результате перевода (трансляции) текстапрограммы каждая секция будет превращена в последовательность байт. Призапуске программы каждая такая последовательность байт будет загружена воперативную память и размещена в выделенных для нее ячейках памяти.Операционная система выделяет отдельные блоки памяти под машинныекоманды, константы, переменные трех классов памяти (в терминологии языка Си):статические, автоматические, динамические.
Секции ассемблерного файласодержат только машинные команды, константы и статические переменные,память для «кучи» и автоматических переменных в начальный момент работыпрограммы выделяется операционной системой. Эта память доступна дляиспользования, но изначально ничем не заполнена, т.е. содержит произвольныезначения.Способ записи машинных команд и определения данных в секциях исходного(текстового) файла определяется синтаксисом ассемблера.
Для архитектуры IA-32существует два основных синтаксиса: AT&T и Intel. Каждая конкретная реализацияассемблера вносит свои изменения в синтаксис, образуя диалект.В рамках данного курса рассматривается ассемблер NASM (Netwide Assembler),версии которого существуют под большое количество платформ, включая Microsoft8Windows и различные виды UNIX-систем. Скачать ассемблер и документацию кнему можно с официального сайта http://www.nasm.us/.Программы на языке ассемблера представляют собой текстовые файлы срасширением .asm.
Как уже говорилось, файл состоит из нескольких секций, вкоторых размещается код программы (последовательность ассемблерныхинструкций) и её данные.В простых программах набор секций, как правило, ограничен тремя (не считаяслужебных):секция кода, которая обычно называется .text;секция инициализированных данных (то есть тех, для которых определеноначальное значение), которая обычно называется .data;секция неинициализированных данных, значения которых обнуляютсяоперационной системой перед запуском программы; эта секция обычноназывается .bss.В ассемблерном файле могут присутствовать и другие секции.
Например, можетбыть несколько секций кода или данных, однако мы такие программырассматривать не будем. Программа воспринимается построчно. Каждая строка,как и во многих других ассемблерах, представляет собой последовательностьследующих полей:метка — присваивает имя данному месту в программе, вне зависимости оттого, что на этом месте расположено (код/данные);ассемблерная инструкция, состоит из кода операции и операндов (если ониесть), перечисляемых через запятую;директива определения данных;комментарий.Допустимы пустые строки.
Кроме того, на отдельных строках могут быть записаныслужебные директивы, указывающие ассемблеру, каким образом следуетразмещать код и данные в памяти.Ассемблерная инструкцияСтрока с описанием ассемблерной инструкции имеет следующий вид:метка:код_опреации операнды; комментарийИмена меток не должны повторяться (за исключением локальных меток, которыебудут рассмотрены во второй части пособия). Допустима ситуация, когдаассемблерная инструкция пропущена и строка содержит только метку сдвоеточием. Такое форматирование текста практикуют для лучшей читаемостиассемблерного кода. Инструкция отделяется от операндов одним или несколькимипробелами или символами табуляции, а операнды, если они есть, должны быть9отделены друг от друга запятыми и, возможно, пробельными символами исимволами табуляции. В конце строки может находиться комментарий,начинающийся с символа «точка с запятой».
Комментарий продолжается до концастроки.Директивы определения данныхСтрока с описанием данных имеет следующий вид:имя_переменной [:]директива_определения_данных; комментарийПри описании данных, после имени переменной может присутствовать двоеточие;фактическое использование ассемблером символьного имени переменной вточности совпадает с использованием меток, помечающих код.Для определения переменных с начальными значениями используются директивыDB, DW, DD и DQ. Например:имя_переменной DD значение1[, значение2, ...
]Директива DB предназначена для определения данных размером в байт, DW, DD иDQ определяют данные размером соответственно в слово (2 байта), двойное слово(4 байта) и учетверенное слово (8 байтов). Например:xdw-1ydd1, 2, 3;;;;Определение переменной x в формате слова сначальным значением -1Определение трех двойных слов с начальнымизначениями 1, 2, 3Последняя директива описывает тот факт, что в памяти, начиная с адреса у,последовательно размещаются три двойных слова с указанными значениями, приэтом первое двойное слово располагается в памяти по адресу y, второе – по адресуy+4, третье – по адресу y+8.В общем случае, через запятую перечисляется набор значений, который будетразмещен в памяти, начиная с адреса, помеченного как имя_переменной.NASM не позволяет указывать неопределенное начальное значение (в MASMe дляэтого служил знак ?).
Если начальное значение переменной не важно, ее следуетрасполагать в секции .bss, все байты которой инициализируются нулем. Такаяособенность позволяет экономить место в файле с исполняемым кодом:содержимое секции заранее известно, достаточно хранить только ее размер. При10объявлении переменных в секции .bss необходимо использоватьсоответствующие директивы: RESB, RESW, RESD и RESQ, имеющие следующийформат.имя_переменной RESB количество_ячеекПод количеством ячеек понимается число байт, слов, двойных или четверных слов,в зависимости от использованной директивы.aresdbresbcresw1;;20 ;;256 ;Выделено местодвойное слово,Выделено место20 байтВыделено местодля одной переменной, ее размер –начальное значения – 0для последовательно размещенныхдля 256 словИмена a, b и c являются адресами, начиная с которых размещены обнуленныеданные.В качестве конструкции повторения в ассемблере NASM используется префиксTIMES (в отличие от DUP в MASMe):TIMES количество_раз повторяемая конструкцияПример – требуется объявить переменную с именем zerobuf, представляющуюсобой буфер размером в 64 байта и заполненный нулями.zerobuf times 64 db 0Аргумент конструкции TIMES не константа, а вычисляемое выражение, чтопозволяет реализовывать, например, следующее:buffer: db ‘hello, world!’times 64-$+buffer db ‘ ’Начиная с метки buffer будет выделено 64 байта, первые байты будут заполненызаданной строкой, остальные – пробелом.