WWW.DISS.SELUK.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА
(Авторефераты, диссертации, методички, учебные программы, монографии)

 

Pages:     || 2 | 3 | 4 |

«АССЕМБЛЕР на примерах Базовый курс Наука и Техника, Санкт-Петербург 2005 Рудольф Марек. Ассемблер на примерах. Базовый курс. — СПб: Наука и Техника, 2005. — 240 с: ил. ISBN 5-94387-232-9 Серия Просто о сложном Эта книга ...»

-- [ Страница 1 ] --

Рудольф Марек

АССЕМБЛЕР

на примерах

Базовый курс

Наука и Техника, Санкт-Петербург

2005

Рудольф Марек.

Ассемблер на примерах. Базовый курс. —

СПб: Наука и Техника, 2005. — 240 с: ил.

ISBN 5-94387-232-9

Серия «Просто о сложном»

Эта книга представляет собой великолепное практическое руководство по основам

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

Вы узнаете, как писать ассемблерные программы под разные операционные системы (Windows, DOS, Linux), как создавать резидентные программы, как писать ассемблерные вставки в программы на языках высокого уровня и многое другое. Попутно вам будут разъяснены основные моменты работы процессора, операционных систем, управления памятью и взаимодействия программ с аппаратными устройствами ПК - то есть все то, без знания чего нельзя обойтись при программировании на языке низкого уровня, которым и является ассемблер.

Книга написана доступным языком. Лучший выбор для начинающих.

Русское издание под редакцией Финкова М.В. и Березкиной О.И.

Copyright © Computer Press 2004 Uiime se programovat vjazyce Assembler pro PC by Rudolf Marek, ISBN: 80-722-6843-0.

All rights reserved Контактные телефоны издательства (812) - 7 0 " 2 5. 567-70- llllllll llllllllli I llll lllll II I (044)516-38- Официальный сайт www.nit.com.ru © Перевод на русский язык, a VQ Vo и 1 У "7 т li t. Наука и Техника, © Издание нерусском языке, оформление, Наука и Техника, ISBN 5-94387-232- 0 0 0 «Наука и Техника».

Лицензия №000350 от 23 декабря 1999 года.

198097, г. Санкт-Петербург, ул. Маршала Говорова, д. 29.

Подписано в печать 08.08.05. Формат 70x100 1/16.

Бумага газетная. Печать офсетная. Объем 15 п. л.

Тираж 5000 экз. Заказ № Отпечатано с готовых диапозитивов в ОАО «Техническая книга»

190005, Санкт-Петербург, Измайловский пр., Содержание Введение Глава 1. Базовые системы счисления и термины 1.1. Системы счисления и преобразования между ними 1.2. Типы данных. Их представление в компьютере Глава 2. Введение в семейство процессоров х86 2.1. О компьютерах 2.2. История процессоров х86 2.3. Процессоры и их регистры: общая информация 2.4. Процессор 80386 Регистры общего назначения Индексные регистры Сегментные регистры Регистры состояния и управления 2.5 Прерывания Глава 3. Анатомия команд и как они выполняются процессором 3.1. Как команды выполняются процессором 3.2. Операнды 3.3. Адресация памяти 3.4. Команды языка ассемблера 4.3.2. Команды инкрементирования INC и декрементирования DEC Псевдокоманда TIMES — повторение следующей псевдокоманды.. к Глава 7. Полезные фрагменты кода Директивы SECTION и SEGMENT — задание структуры программы... 10.11.1. Что такое отладка программы и зачем она нужна 11.2.2. Программа «Hello, World!» с кнопкой под Windows 12.3. Передача параметров командной строки и переменных окружения 12.12. Ввод с клавиатуры. Изменение поведения потока стандартного ввода.

Глава 13. Компоновка — стыковка ассемблерных программ Эта книга — начальный курс и практическое руководство по програм­ мированию на языке ассемблера для процессоров серии х86 — самых распространенных в современных ПК. Она предназначена для студентов и старшеклассников, которые хотят познакомиться с языком программирования низкого уровня, позволяющим писать компактные, быстрые и эффективные программы, взаимодействующие с аппаратным обеспечением компьютера напрямую, минуя любую операционную систему.

Книга содержит подробные объяснения и множество практических при­ меров.

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

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

Книга написана простым, доступным языком, а все примеры программ тщательно прокомментированы.

Особое внимание обращено на следующие вопросы:

• Архитектура процессора, функции операционной системы, машинный код и символическое представление команд и адресов;

• Различные системы счисления и перевод чисел из одной в другую;

• Основные и сложные команды;

• Управляющие конструкции и их реализация;

• Готовые фрагменты кода, выполняющие самые типичные задачи;

•Использование свободно распространяемого компилятора Netwide Assembler (NASM);

• Практическое программирование в среде DOS, Windows и Linux;

• Написание ассемблерных вставок в программы на языках высокого уровня (С и Паскаль).



Автор книги — деятельный разработчик свободного программного обес­ печения, соавтор самого маленького в мире веб-сервера размером в 514 байт, участник разработки пакета Asmutils и создатель программного модуля для Linux-проигрывателя MPlayer.

Базовые системы счисления и термины Системы счисления и преобразования между ними Типы данных. Их представление в компьютере Архитектура компьютера тесно связана с двоичной системой счисления, кото­ рая состоит всего из двух цифр — 0 и 1. С технической точки зрения, двоичная система (с основой 2) идеально подходит для компьютеров, поскольку обе цифры могут отображать два состояния — включено (1) и выключено (0).

Как мы вскоре увидим, «большие» числа становятся огромными в двоичной системе, поэтому для более удобного представления чисел были разработаны восьмеричная и шестнадцатеричная системы счисления (с основами 8 и соответственно). Обе системы легко преобразуются в двоичную систему, но позволяют записывать числа более компактно.

Различные системы счисления отличаются не только базовым набором чисел, но и основными концепциями, которые лежат в их основе. Взять, например, систему счисления, которая использовалась древними римлянами: она до­ вольно трудна для восприятия, в ней очень сложно производить вычисления и невозможно представить 0. Данная система неудобна даже для человека, не говоря уж о том, чтобы научить компьютер «понимать» ее.

Десятичная система, которую мы используем всю жизнь, относится к классу так называемых позиционных систем, в которых число А может быть пред­ ставлено в виде:

Здесь an — это цифры числа, a Z — основание системы счисления, в нашем случае — 10.

Например, число 1234 можно представить так:

«Вес» каждой цифры определяется позицией цифры в числе и равен степени основания, соответствующей ее позиции.

При работе с различными системами счисления мы будем записывать само число в скобках, а за скобками — основание системы. Например, если напи­ сать просто число 1100, то не понятно, в какой системе оно записано — это может быть одна тысяча сто, а может быть 12, если число записано в двоичной системе. А если представить число в виде (1100)2, то сразу все становится на свои места: число записано в двоичной системе. Кстати, двоичная система тоже является позиционной, поэтому число 1100 в двоичной системе мы можем представить так:

После сложения 8+4 мы получим, что (1100)2 равно 12. Как видите, все точно так же, как и с десятичной системой. Обратите внимание, что для представ­ ления числа 12 в двоичной системе использованы только четыре разряда.

Наибольшее число, которое можно записать четырьмя двоичными цифрами, равно 15, потому что (1Ш) 2 = I* 8 + I* 4 + I* 2 + 1*' = 15. Давайте рассмотрим первые 16 чисел:

Числа растут равномерно, и нетрудно предположить, что 16 будет представ­ лено в двоичной системе как (10000)2.

Восьмеричная система счисления (по основанию 8) состоит из большего количества цифр — из восьми (от 0 до 7). Преобразование из этой системы в десятичную систему полностью аналогично преобразованию из двоичной системы, например:

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

В шестнадцатеричной системе цифрами представлены только первые 10 чисел, а для представления остальных 5 чисел используются символы A-F:

Ассемблер на примерах. Базовый курс Представим, как изменяется наш возраст в шестнадцатеричной системе: вы получили свой паспорт в 10 лет и стали совершеннолетним в 12 лет.

Для шестнадцатеричной системы сохраняются те же принципы преобразования:

Число (524D)16 = 5*163 + 2*162 + 4*16» + 13*16° = Число (DEAD) 16 ш 13*163 + 14*162 + 10*16' + 13*16° = Число (DEADBEEF)16 = 13*167 + 14*166 + 10*165 + 13*164 + Итак, мы научились преобразовывать любое число, представленное в двоич­ ной, восьмеричной и шестнадцатеричной системах, в десятичную систему.

А теперь займемся обратным преобразованием — из десятичной системы в систему с основанием п. Для обратного преобразования мы должны делить наше число на п и записывать остатки от деления до тех пор, пока частное от предыдущего деления не станет равно 0. Например, преобразуем 14 в двоичную систему:

Мы завершили процесс деления, когда последнее частное стало равно 0.

Теперь запишем все остатки подряд от последнего к первому, и мы получим число в двоичной системе — (1110)2.

Рассмотрим еще один пример — преобразование числа 13 в двоичную систему:

Как и в прошлом случае, мы делили до тех пор, пока частное не стало равно 0. Если записать остатки снизу вверх, мы получим двоичное число (1101)2.

А теперь потренируемся с шестнадцатеричной системой — преобразуем число 123456 в эту систему:

После записи всех остатков получим, что число 123 456 = (1Е240)16.

Запись со скобками и нижним индексом в тексте программы неудобна, по­ этому мы будем использовать следующие обозначения для записи чисел в различных системах счисления:

• Запись шестнадцатиричного числа начинается с Ох или $0 либо заканчи­ вается символом «h». Если первая цифра шестнадцатеричного числа — символ A-F, то перед таким числом нужно обязательно написать 0, чтобы компилятор понял, что перед ним число, а не идентификатор, например, ODEADh.

Таким образом, записи 0x1234, $01234 и 01234h представляют число (1234)16.

• Десятичные числа могут записываться без изменений либо они закан­ чиваться постфиксом «d». Например, 1234 и 1234d представляют число (1234)ш.

• Двоичные цифры должны заканчиваться постфиксом «Ь», например, ПООЬ — это (1100),.

• Восьмеричные цифры заканчиваются на «q»: 12q — это (12)8.

Далее в этой книге шестнадцатеричные числа мы будем записывать в виде «0х...», двоичные — «...Ь», а десятичные — без изменений. В вашем соб­ ственном коде основание системы счисления (постфикс «d» или «h») лучше указывать явно, потому что одни ассемблеры рассматривают число без при­ ставок как десятичное, а другие — как шестнадцатеричное.

Их представление в компьютере Основной и неделимой единицей данных является бит. Слово «bit» — это сокращение от «binary digit» — двоичная цифра. Бит может принимать два значения — 0 и 1 — ложь или истина, выключено или включено. На логике двух состояний основаны все логические цепи компьютеров, поэтому пого­ ворим о бите более подробно.

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

Ассемблер на примерах. Базовый курс Биты (разряды) двоичного числа нумеруются справа налево, от наименее зна­ чимого до наиболее значимого. Нумерация начинается с 0. Самый правый бит числа — это бит с номером 0 (первый бит). Этот бит называется LSB-битом (Least Significant Bit — наименее значимый бит). Подобно этому самый левый бит называется MSB-битом (Most Significant Bit — наиболее значимый бит).

Биты могут объединяться в группы, группа из четырех битов называется по­ лубайтом (nibble). Компьютер не работает с отдельными битами, обычно он оперирует группами битов, например, группа из восьми битов образует базо­ вый тип данных, который называется байтом. Восемь битов в байте — это не закон природы, а количество, произвольно выбранное разработчиками IBM, создававшими первые компьютеры.

Большие группы битов называются словом (word) или двойным словом (dword — double word). Относительно PC-совместимых компьютеров мы можем сказать следующее:

1 двойное слово (dword) = 4 байта = 32 бит Один байт — это наименьшее количество данных, которое может быть про' читано из памяти или записано в нее, поэтому каждый байт памяти имеет индивидуальный адрес. Байт может содержать число в диапазоне 0 — 255 (то есть 28 — 256 различных чисел). В большинстве случаев этого значения недо-' статочно, поэтому используется следующая единица данных — слово. Слово может содержать число в диапазоне 0 — 65 535 (то есть 216 = 65 536 различив~ значений). Двойное слово имеет диапазон значений 0 — 4 294 967 295 (232 Щ 4 294 967 296 значений).

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

Решили, что емкость будет выражаться в килобайтах (KB, Kb, Кб или просто к).

Но, в отличие от международной системы SI, приставка «кило» означает не 1000, а 1024. Почему именно 1024? Поскольку все в компьютере было завя­ зано на двоичной системе, для простоты любое значимое число должно было выражаться как степень двойки. 1024 — это 210. Следующие приставки — М (мегабайт, MB, Mb, Мб), G (гигабайт, GB, Гб), Т (терабайт, ТВ, ТБ) и Р (петабайт, РВ, ПБ) — вычисляются умножением 1024 на предыдущее значе­ ние, например, 1 Кб = 1024, значит, 1 Мб = 1 Кб * 1024 = 1024 * 1024 - 576 байт. Думаю, с этим все понятно, давайте вернемся к типам данных.

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

Тут все просто. Каждое значение байта соответствует одному из символов ASCII-таблицы (American Standard Code for Information Interchange). Первые 128 символов — управляющие символы, латинские буквы, цифры — одинаковы для всех компьютеров и операционных систем. Давайте рассмотрим таблицу кодов ASCII (рис. 1.2).

Шестнадцатеричные цифры в заголовках строк и столбцов таблицы пред­ ставляют числовые значения отдельных символов. Например, координаты заглавной латинской буквы А — 40 и 01. Сложив эти значения, получим 0x (то есть 65 в десятичной системе) — код символа 'А' в ASCII-коде.

Печатаемые символы в ASCII-таблице начинаются с кода 0x20 (или 32d). Сим­ волы с кодом ниже 32 представляют так называемые управляющие символы.

Наиболее известные из них — это ОхА или LF — перевод строки, и OxD — CR — возврат каретки.

Важность управляющих символов CR и LF обусловлена тем, что они обо­ значают конец строки — тот символ, который в языке программирования С обозначается как \п. К сожалению, в различных операционных системах он представляется по-разному: например, в Windows (и DOS) он представляется двумя символами (CR, LF — OxD, ОхА), а в операционной системе UNIX для обозначения конца строки используется всего один символ (LF — ОхА).

Символы с кодами от 128 до 256 и выше стали «жертвами» различных стан­ дартов и кодировок. Обычно они содержат национальные символы, например, у нас это будут символы русского алфавита и, возможно, некоторые символы псевдографики, в Чехии — символы чешского алфавита и т.д. Следует от­ метить, что для русского языка используются кодировки СР 866 (в DOS) и СР 1251 (Windows).

Ассемблер на примерах. Базовый курс Введение в семейство процессоров х О компьютерах..

История процессоров х Процессоры и их регистры:

общая информация Процессор Прерывания Мы начинаем знакомиться с языком ассемблера. Это язык программирования низкого уровня, то есть максимально приближенный к «железу» — аппарат­ ному обеспечению компьютера. Для каждого процессора характерен свой уникальный набор действий, которые процессор способен выполнить, поэтому языки ассемблера разных процессоров отличаются друг от друга. Например, если процессор не умеет выполнять умножение, то в его языке ассемблера н будет отдельной команды «умножить», а перемножать числа программисту придется при помощи нескольких команд сложения.

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

Вот почему, прежде чем приступать к изучению команд языка ассемблера, нам нужно побольше узнать о процессоре, для которого этот язык предна-;

значен.

Первым популярным компьютером стал компьютер ENIAC (Electron' Numerical Integrator And Calculator), построенный из электронных ламп предназначенный для решения дифференциальных уравнений. Программи рование этого компьютера, которое заключалось в переключении тумблеров было очень трудоемким процессом.

Следующим компьютером после ENIAC был не столь популярный EDVA (Electronic Discrete Variable Automatic Computer), построенный в 1946 г Принципы, заложенные в этом компьютере, используются и по сей день: э машина, подобно современным компьютерам, хранила заложенную програ му в памяти. Концепция компьютера EDVAC, разработанная американски ученым венгерского происхождения Джоном фон Нейманом, основывала на следующих принципах:

1. Компьютер должен состоять из следующих модулей: управляющий бло (контроллер), арифметический блок, память, блоки ввода/вывода.

2. Строение компьютера не должно зависеть от решаемой задачи (это как раз относится к ENIAC), программа должна храниться в памяти.

3. Инструкции и их операнды (то есть данные) должны также храниться в той же памяти (гарвардская концепция компьютеров, основанная на концепции фон Неймана, предполагала отдельную память для про­ граммы и данных).

4. Память делится на ячейки одинакового размера, порядковый номер ячейки считается ее адресом (1 ячейка эквивалентна 1 байту).

5. Программа состоит из серии элементарных инструкций, которые обыч­ но не содержат значения операнда (указывается только его адрес), поэтому программа не зависит от обрабатываемых данных (это уже прототип переменных). Инструкции выполняются одна за другой, в том порядке, в котором они находятся в памяти (к слову, современные микропроцессоры позволяют параллельное выполнение нескольких инструкций).

6. Для изменения порядка выполнения инструкций используются инструк­ ции условного или безусловного (jump) перехода.

7. Инструкции и данные (то есть операнды, результаты или адреса) пред­ ставляются в виде двоичных сигналов и в двоичной системе счисле­ Оказалось, что концепция фон Неймана настолько мощна и универсальна, что она до сих пор используется в современных компьютерах.

Однако продвижение компьютера в наши дома потребовало долгого времени — почти сорока лет. В 1950-ых годах был изобретен транзистор, который заменил большие, склонные ко всяким сбоям, вакуумные лампы. Со временем размер транзисторов уменьшился, но самым большим их компонентом оставался кор­ пус. Решение было простым: разместить много транзисторов в одном корпусе.

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

В конце 1970-ых интегральные микросхемы упали в цене до такой степени, что стали доступны рядовым потребителям. Почему же люди в то время не покупали персональные компьютеры? Потому что их не было в продаже! Люди покупали микросхемы и собирали простые восьмиразрядные компьютеры в порядке хобби — так, в знаменитом гараже, началась история фирмы Apple.

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

В 1981 году лидером рынка универсальных ЭВМ — компанией IBM — был выпущен персональный компьютер IBM PC XT. Это был полноценный пер­ сональный компьютер — с монитором, клавиатурой и системным блоком.

Компьютер IBM PC XT был оборудован 8-разрядным микропроцессором Intel 8088. Эта модель стала началом огромной серии персональных компью­ теров (PC, Personal Computer), которые производились вплоть до нашего времени.

История первых 16-разрядных процессоров класса х86, 8086, была начата компанией Intel в 1978 году. Чипы того времени работали на частоте 5, 8 или 10 МГц и благодаря 20-разрядной шине адреса позволяли адресовать 1 Мб оперативной памяти.

В то время были популярны 8-битные компьютеры, поэтому Intel разработала другой чип — 8088, который был аппаратно и программно совместим с 8086, но оснащен только 8-разрядной шиной.

В 1982 году Intel представила процессор 80286, который был обратно совме­ стим с обеими предыдущими моделями, но использовал более «широкую», 24-разрядную, шину адреса. Этот процессор позволял адресовать 16 Мб опе­ ративной памяти. Кроме расширенного набора команд (появилось несколько новых команд), данный процессор мог работать в двух режимах — реальном и защищенном.

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

Четыре года спустя, в 1986 году, Intel выпустила процессор 80386 DX, у которо­ го обе шины (шина данных и шина адреса) были 32-разрядными. В то же время был выпущен процессор 80386 SX, который был во всем идентичен 80386 DX, но только с 16-разрядной внешней шиной данных. Оба процессора работали на частоте 20, 25 или 33 МГц. Процессор 80386 не имел интегрированного математического сопроцессора, математический сопроцессор поставлялся в виде отдельного чипа — 80387.

В 1989 году было выпущено следующее поколение микропроцессоров Intel — 80486DX, 80486DX/2 и 80486DX/4, которые отличались только рабочей часто­ той. Выпущенная тогда же версия 80486SX, в отличие от 80486DX, постав­ лялась без математического сопроцессора. Новые возможности интеграции позволили разместить на чипе 8 Кб кэш-памяти.

В 1993 году был выпущен первый чип под названием Pentium. С него началась новая линия чипов, которые не только используются сейчас, но и все еще могут выполнять программы, написанные 20 лет назад для процессора 8086.

Процессоры, совместимые с х86, выпускались не только компанией Intel, но также и другими компаниями: AMD, Cyrix, NEC, IBM. Мы более подробно рассмотрим 80386, который с точки зрения программирования полностью совместим даже с самыми современными процессорами.

2.3. Процессоры и их регистры:

Поговорим о внутреннем строении процессора. Процессор — это кремниевая плата или «подложка» с логическими цепями, состоящими из транзисторов, скрытая в пластмассовом корпусе, снабженном контактными ножками (вы­ водами, pin). Большинство ножек процессора подключено к шинам — шине адреса, шине данных и шине управления, связывающим чип процессора с остальной частью компьютера. Остальные ножки служат для подачи питания на сам чип. Каждая шина состоит из группы проводников, которые выполняют определенную функцию.

Пункт 7 концепции фон Неймана говорит: ИНСТРУКЦИИ И ДАННЫЕ

(ТО ЕСТЬ ОПЕРАНДЫ, РЕЗУЛЬТАТЫ ИЛИ АДРЕСА) ПРЕДСТАВЛЯ­

ЮТСЯ В ВИДЕ ДВОИЧНЫХ СИГНАЛОВ И В ДВОИЧНОЙ СИСТЕМЕ

СЧИСЛЕНИЯ.

Это означает, что один проводник шины компьютера может «нести» один бит. Значение этого бита (1 или 0) определяется уровнем напряжения в проводнике. Значит, процессор с одной 16-разрядной шиной и одной 8-раз­ рядной должен иметь 24 (16 и 8) ножки, соединенные с различными прово­ дниками. Например, при передаче числа 27 (00011011 в двоичной системе) по 8-разрядной шине проводник, по которому передается самый правый бит (LSB), покажет логический уровень 1, следующий провод также покажет 1, следующий — 0 и т.д.

Ассемблер на примерах. Базовый курс Пока мы сказали, что процессор состоит из логических контуров. Эти цепи реализуют все модули, из которых процессор должен состоять согласно кон­ цепции фон Неймана: контроллер, арифметико-логическое устройство (АЛУ) и регистры.

Контроллер управляет получением инструкций из памяти и их декодировани­ ем. Контроллер не обрабатывает инструкцию: после декодирования он про­ сто передает ее по внутренней шине управления к другим модулям, которые выполняют необходимое действие.

Арифметико-логическое устройство (АЛУ) выполняет арифметические и ло­ гические действия над данными. Для более простых процессоров достаточно АЛУ, умеющего выполнять операции отрицания и сложения, поскольку другие арифметические действия (вычитание, умножение и целочисленное деление) могут быть сведены к этим операциям.

Другая, логическая, часть АЛУ выполняет основные логические действия над данными, например, логическое сложение и умножение (ИЛИ, И), а также исключительное ИЛИ. Еще одна функция АЛУ, которую выполняет устройство циклического сдвига (barrel-shifter), заключается в сдвигах битов влево и вправо.

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

Среди регистров обязательно должны присутствовать следующие группы:

регистры общего назначения, регистры состояния и счетчики. Регистры обще­ го назначения содержат рабочие данные, полученные из памяти. Регистры состояния содержат текущее состояние процессора (или состояние АЛУ).

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

Микропроцессор 80386 полностью 32-разрядный, что означает, что он может работать с 4 Гб оперативной памяти (232 байтов). Поскольку шина данных также 32-разрядная, процессор может обрабатывать и хранить в своих реги­ страх число «шириной» в 32 бита (тип данных int в большинстве реализаций языка С как раз 32-разрядный).

Чтобы научиться программировать на языке ассемблера, мы должны знать имена регистров (рис. 2.3) и общий принцип работы команд. Сами команды обсуждаются в следующих главах.

Сначала рассмотрим регистры общего назначения. Они называются ЕАХ, ЕВХ, ЕСХ и EDX (Аккумулятор, База, Счетчик и Данные). Кроме названий, они больше ничем другим не отличаются друг от друга, поэтому рассмотрим только первый регистр — ЕАХ (рис. 2.4).

Процессор 80386 обратно совместим с процессором 80286, регистры которого 16-разрядные. Как же 80386 может выполнять команды, предназначенные для регистров меньшего размера? Регистр ЕАХ может быть разделен на две части — 16-разрядный регистр АХ (который также присутствует в 80286) и верхние 16 битов, которые никак не называются. В свою очередь, регистр АХ может быть разделен (не только в 80386, но и в 80286) на два 8-битных регистра — АН и AL.

Если мы заносим в регистр ЕАХ значение 0x12345678, то регистр АХ будет содержать значение 0x5678 (0x56 в АН и 0x78 в AL), а значение 0x1234 будет помещено в верхнюю часть регистра ЕАХ.

«Младшие» регистры других регистров общего назначения называются по такому же принципу: ЕВХ содержит ВХ, который, в свою очередь, содержит ВН и BL и т.д.

Ассемблер на примерах. Базовый курс К регистрам общего назначения иногда относят и индексные регистры про­ цессора 80386 — ESI, EDI и ЕВР (или SI, DI и ВР для 16-разрядных действий).

Обычно эти регистры используются для адресации памяти: обращения к массивам, индексирования и т.д. Отсюда их имена: индекс источника (Source Index), индекс приемника (Destination Index), указатель базы (Base Pointer).

Но хранить в них только адреса совсем необязательно: регистры ESI, EDI и ЕВР могут содержать произвольные данные. Эти регистры программно до­ ступны, то есть их содержание может быть изменено программистом. Другие регистры лучше «руками не трогать».

У регистров ESI, EDI и ЕВР существуют только в 16-разрядная и 32-разряд­ ная версии.

Эту группу регистров можно отнести к регистрам состояния. Регистры из этой группы используются при вычислении реального адреса (адреса, который будет передан на шину адреса). Процесс вычисления реального адреса зави­ сит от режима процессора (реальный или защищенный) и будет рассмотрен в следующих главах. Сегментные регистры только 16-разрядные, такие же, как в 80286.

Названия этих регистров соответствуют выполняемым функциям: CS (Code Segment, сегмент кода) вместе с EIP (IP) определяют адрес памяти, откуда нужно прочитать следующую инструкцию; аналогично регистр SS (Stack Segment, сегмент стека) в паре с ESP (SS:SP) указывают на вершину стека.

Сегментные регистры DS, ES, FS, и GS (Data, Extra, F и G сегменты) исполь­ зуются для адресации данных в памяти.

Регистр ESP (SP) — это указатель памяти, который указывает на вершину стека (х86-совместимые процессоры не имеют аппаратного стека). О стеке мы поговорим в следующих главах. Также программно не может быть изменен регистр EIP (IP, Instruction Pointer) — указатель команд. Этот регистр ука­ зывает на инструкцию, которая будет выполнена следующей. Значение этого регистра изменяется непосредственно контроллером процессора согласно инструкциям, полученным из памяти.

Нам осталось рассмотреть только регистр флагов (иногда его называют реги­ стром признаков) — EFLAGS. Он состоит из одноразрядных флагов, отобра­ жающих в основном текущее состояние арифметико-логического устройства.

В наших программах мы будем использовать все 32 флага, а пока рассмотрим только самые важные из них:

Ассемблер на примерах. Базовый курс • Признак нуля ZF (Zero Flag) — 1, если результат предыдущей операции равен нулю.

• Признак знака SF (Sign Flag) — 1, если результат предыдущей операции отрицательный.

• Признак переполнения OF (Overflow Flag) — 1, если при выполнении предыдущей операции произошло переполнение (overflow), то есть результат операции больше, чем зарезервированная для него память.

• Признак переноса CF (Carry Flag) — 1, если бит был «перенесен» и стал битом более высокого порядка (об этом мы поговорим в четвертой главе, когда будем рассматривать арифметические операции).

• Признак прерывания IF (Interrupt Flag) — 1, если прерывания процес­ сора разрешены.

• Признак направления DF (Direction Flag) — используется для обработки строк, мы рассмотрим подробнее этот регистр в шестой главе.

Другие регистры процессора относятся к работе в защищенном режиме, описание принципов которого выходит за рамки этой книги.

Если 80386 процессор оснащен математическим сопроцессором 80387 (это отдельный чип на вашей материнской плате), он будет быстрее обрабатывать числа с плавающей точкой.

Современным процессорам отдельный математический процессор не нужен — он находится «внутри» процессора. Раньше вы могли немного сэкономить и купить компьютер без математического сопроцессора — его наличие было необязательно, и компьютер мог работать без него. Если математический процессор не был установлен, его функции эмулировались основным про­ цессором, так что производительность операций над числами с плавающей точкой была очень низкой.

Когда мы будем говорить сразу о 16- и 32-разрядных регистрах, то мы будем использовать сокращение (Е)АХ) — вместо АХ и ЕАХ.

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

Давайте рассмотрим пример. Я сижу за столом и читаю книгу. С точки зрения компьютера, я выполняю процесс чтения книги. Внезапно звонит телефон — я прерываю чтение, кладу в книгу закладку (на языке процессора это назы­ вается «сохранить контекст») и беру трубку. Теперь я «обрабатываю» теле­ фонный звонок. Закончив разговор, я возвращаюсь к чтению книги. Найти последнее прочитанное место помогает та самая закладка.

Процессоры семейства х86 и совместимые с ними могут порождать 256 преры­ ваний. Адреса всех 256 функций обработки прерываний (так называемые век­ торы прерываний) хранятся в специальной таблице векторов прерываний.

Прерывания могут быть программными и аппаратными.

Аппаратные прерывания происходят по запросу периферийных устройств и называются IRQ (Interrupt Requests). Архитектура шины ISA ограничивает их число до 16 (IRQ0 — IRQ15).

К аппаратным прерываниям относятся также специальные прерывания, которые генерирует сам процессор. Такие прерывания используются для обработки «исключительных ситуаций» — неверный операнд, неизвестная команда, переполнение и другие непредвиденные операции, когда процессор сбит с толку и не знает, что делать. Эти прерывания имеют свои обозначения и никак не относятся к зарезервированным для периферии прерываниям IRQ0-IRQ15.

Все аппаратные прерывания можно разделить на две группы: прерывания, которые можно игнорировать («замаскировать») и те, которые игнорировать нельзя. Первые называются маскируемыми (maskable), а вторые — немаски­ руемыми (non-maskable). Аппаратные прерывания могут быть отключены путем установки флага IF регистра признаков в 0. Единственное прерывание, которое отключить нельзя — это NMI, немаскируемое прерывание, генери­ рующееся при сбое памяти, сбое в питании процессора и подобных форсмажорных обстоятельствах.

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

Анатомия команд и как они выполняются процессором Как команды выполняются процессором Операнды Адресация памяти Команды языка ассемблера 3.1. Как команды выполняются Команда микропроцессора — это команда, которая выполняет требуемое действие над данными или изменяет внутреннее состояние процессора.

Существует две основные архитектуры процессоров. Первая называется RISC (Reduced Instruction Set Computer) — компьютер с уменьшенным набором ко­ манд. Архитектура RISC названа в честь первого компьютера с уменьшенным набором команд — RISC I. Идея этой архитектуры основывается на том, что процессор большую часть времени тратит на выполнение ограниченного числа инструкций (например, переходов или команд присваивания), а остальные команды используются редко.

Разработчики RISC-архитектуры создали «облегченный» процессор. Благодаря упрощенной внутренней логике (меньшему числу команд, менее сложным логическим контурам), значительно сократилось время выполнения отдельных команд и увеличилась общая производительность. Архитектура RISC подобна «архитектуре общения» с собакой — она знает всего несколько команд, но выполняет их очень быстро.

Вторая архитектура имеет сложную систему команд, она называется CISC (Complex Instruction Set Computer) — компьютер со сложной системой ко­ манд. Архитектура CISC подразумевает использование сложных инструкций, которые можно разделить на более простые. Все х86-совместимые процессоры принадлежат к архитектуре CISC.

Давайте рассмотрим команду «загрузить число 0x1234 в регистр АХ». На языке ассемблера она записывается очень просто — MOV АХ, 0x1234. К на­ стоящему моменту вы уже знаете, что каждая команда представляется в виде двоичного числа (пункт 7 концепции фон Неймана). Ее числовое представ­ ление называется машинным кодом. Команда MOV АХ, 0x1234 на машинном языке может быть записана так:

Ассемблер на примерах. Базовый курс 0x11хх: предыдущая команда 0x1111: 0хВ8, 0x34, 0x 0x1114: следующие команды Мы поместили команду по адресу 0x1111. Следующая команда начинается тремя байтами дальше, значит, под команду с операндами отведено 3 бай­ та. Второй и третий байты содержат операнды команды MOV. А что такое 0хВ8? После преобразования 0хВ8 в двоичную систему мы получим значение ЮШОООЬ.

Первая часть — 1011 — и есть код команды MOV. Встретив код 1011, кон­ троллер «понимает», что перед ним — именно MOV. Следующий разряд (1) означает, что операнды будут 16-разрядными. Три последние цифры опреде­ ляют регистр назначения. Три нуля соответствуют регистру АХ (или AL, если предыдущий бит был равен 0, указывая таким образом, что операнды будут 8-разрядными).

Чтобы декодировать команды, контроллер должен сначала прочитать их из памяти. Предположим, что процессор только что закончил выполнять пред­ шествующую команду, и IP (указатель команд) содержит значение 0x1111.

Прежде чем приступить к обработке следующей команды, процессор «по­ смотрит» на шину управления, чтобы проверить, требуются ли аппаратные прерывания.

Если запроса на прерывание не поступало, то процессор загружает значение, сохраненное по адресу 0x1111 (в нашем случае — это 0хВ8), в свой внутренний (командный) регистр. Он декодирует это значение так, как показано выше, и «понимает», что нужно загрузить в регистр АХ 16-разрядное число — два следующих байта, находящиеся по адресам 0x1112 и 0x1113 (они содержат наше число, 0x1234). Теперь процессор должен получить из памяти эти два байта. Для этого процессор посылает соответствующие команды в шину и ожидает возвращения по шине данных значения из памяти.

Получив эти два байта, процессор запишет их в регистр АХ. Затем процессор увеличит значение в регистре IP на 3 (наша команда занимает 3 байта), снова проверит наличие запросов на прерывание и, если таких нет, загрузит один байт по адресу 0x1114 и продолжит выполнять программу.

Если запрос на прерывание поступил, процессор проверит его тип, а также значение флага IF. Если флаг сброшен (0), процессор проигнорирует преры­ вание; если же флаг установлен (1), то процессор сохранит текущий контекст и начнет выполнять первую инструкцию обработчика прерывания, загрузив ее из таблицы векторов прерываний.

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

Глава 3. Анатомия команд и как они выполняются процессором Данные, которые обрабатываются командами, называются операндами. Опе­ ранды в языке ассемблера записываются непосредственно после команды;

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

В качестве операнда можно указать непосредственное значение (например, 0x123), имя регистра или ссылку на ячейку памяти (так называемые косвен­ ные операнды).

Что же касается разрядности, имеются 32-разрядные, 16-разрядные, и 8-раз­ рядные операнды. Почти каждая команда требует, чтобы операнды были одинакового размера (разрядности). Команда MOV АХ, 0x1234 имеет два операнда: операнд регистра и непосредственное значение, и оба они 16-бит­ ные.

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

В документации по Ассемблеру различные форматы операндов представлены следующими аббревиатурами:

• regS-операнд — любой 8-разрядный регистр общего назначения;

• regl6-onepaHfl — любой 16-разрядный регистр общего назначения;

• reg32-onepaHfl — любой 32-разрядный регистр общего назначения;

• m — операнд может находиться в памяти;

• imm8 — непосредственное 8-разрядное значение;

• imml6 — непосредственное 16-разрядное значение;

• imm32 — непосредственное 32-разрядное значение;

• segreg — операнд должен быть сегментным регистром.

Допускаются неоднозначные типы операндов, например: reg8/imm8-onepaHfl может быть любым 8-битным регистром общего назначения или любым 8-битным непосредственным значением.

Иногда размер операнда определяется только по последнему типу, например, следующая запись аналогична предыдущей: R/imm8-onepaHfl может быть любым регистром (имеется в виду 8-битный регистр) общего назначения или 8-разрядным значением.

2 Зак. Ассемблер на примерах. Базовый курс Мы уже знаем, что адрес, как и сама команда, — это число. Чтобы не запо­ минать адреса всех «переменных», используемых в программе, этим адресам присваивают символические обозначения, которые называются переменными (иногда их также называют указателями).

При использовании косвенного операнда адрес в памяти, по которому на­ ходится нужное значение, записывается в квадратных скобках: [адрес]. Если мы используем указатель, то есть символическое представление адреса, на­ пример, [ESI], то в листинге машинного кода мы увидим, что указатель был заменен реальным значением адреса. Можно также указать точный адрес памяти, например, [0x594F].

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

Теперь рассмотрим фрагмент программы, в которой регистр ESI содержит адрес первого элемента (нумерация начинается с 0) в массиве байтов. Как получить доступ, например, ко второму элементу (элементу, адрес которого на 1 байт больше) массива? Процессор поддерживает сложные способы адре­ сации, которые очень нам пригодятся в дальнейшем. В нашем случае, чтобы получить доступ ко второму элементу массива, нужно записать косвенный операнд [ESI + 1].

Имеются даже более сложные типы адресации: [адрес + ЕВХ + 4]. В этом случае процессор складывает адрес, значение 4 и значение, содержащееся в регистре ЕВХ. Результат этого выражения называется эффективным адресом (ЕА, Effective Address) и используется в качестве адреса, по которому факти­ чески находится операнд (мы пока не рассматриваем сегментные регистры).

При вычислении эффективного адреса процессор 80386 также позволяет умножать один член выражения на константу, являющуюся степенью двойки:

[адрес + ЕВХ * 4]. Корректным считается даже следующее «сумасшедшее»

выражение:

На практике мы будем довольствоваться только одним регистром [ESI] или суммой регистра и константы, например, [ESI + 4]. В зависимости от режима процессора, мы можем использовать любой 16-разрядный или 32-разрядный регистр общего назначения [ЕАХ], [ЕВХ],... [ЕВР].

Процессор предыдущего поколения 80286 позволял записывать адрес в виде суммы содержимого регистра и константы только для регистров ВР, SI, DI, и ВХ.

Глава 3. Анатомия команд и как они выполняются процессором Выше мы упомянули, что в адресации памяти участвуют сегментные регистры. Их функция зависит от режима процессора. Каждый способ адресации предполагает, что при вычислении реального (фактического) адреса используется сегментный регистр по умолчанию. Сменить регистр по умолчанию можно так:

ES:[ESI] Некоторые ассемблеры требуют указания регистра внутри скобок:

[ES:ESI] В наших примерах мы будем считать, что все сегментные регистры содержат одно и то же значение, поэтому мы не будем использовать их при адреса­ ции.

Когда мы знаем, что такое операнд, давайте рассмотрим, как описываются команды языка ассемблера. Общий формат такой:

имя_команды [подсказка] операнды В следующих главах мы поговорим об отдельных командах и выполняемых ими функциях. Операнды мы только что рассмотрели, осталась одна «темная лошадка» — подсказка. Необязательная подсказка указывает компилятору требуемый размер операнда. Ее значением может быть слово BYTE (8-битный операнд), WORD (16-битный) или DWORD (32-битный).

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

mov dword [ 0x12345678 ],0 ;записывает 4 нулевых байта, mov word [ 0x12345678 ],0 ;записывает 2 нулевых байта, mov b y t e [ 0x12345678 ],0 ;записывает 1 нулевой байт В языке ассемблера точка с запятой является символом начала комментария.

Первая инструкция последовательно запишет 4 нулевых байта, начиная с адреса 0x12345678. Вторая инструкция запишет только два нулевых байта, поскольку размер операнда — слово. Последняя инструкция запишет только один байт (в битах: 00000000) в ячейку с адресом 0x12345678.

Основные команды языка ассемблера Команда MOV «Остроконечники» и «тупоконечник Арифметические команды Логические команды Ассемблер на примерах.

Базовый курс В этой главе рассмотрены основные команды процессоров семейства х86, ко­ торые являются фундаментом и простых, и сложных программ, написанных на языке ассемблера. Мы не только опишем синтаксис команд, но и приведем несколько практических примеров, которые пригодятся вам при написании собственных программ.

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

Команда MOV, хоть название ее и происходит от слова «move» (переме­ щать), на самом деле не перемещает, а копирует значение из источника в приемник:

MOV приемник, источник Рассмотрим несколько примеров применения команды MOV:

mov a x, [ n u m b e r ]заносим значение переменной number mov [number],bx загрузить значение регистра ВХ mov e s i, e d i копировать значение регистра EDI mov word [number] сохранить 16-битное значение Процессоры семейства х86 позволяют использовать в командах только один косвенный аргумент. Следующая команда копирования значения, находя­ щегося по адресу number_one, в область памяти с адресом number_two, недопустима:

mov [number_two], [number_one] ;НЕПРАВИЛЬНО!!!

Ассемблер на примерах. Базовый курс Чтобы скопировать значение из одной области памяти в другую, нужно ис­ пользовать промежуточный регистр:

mov ax, [number_one] ;загружаем в АХ 16-битное mov [number_two], ах ;а затем копируем его в переменную Оба операнда команды MOV должны быть одного размера:

Для копирования значения BL в регистр АХ мы должны «расширить диапа­ зон», то есть скопировать весь ВХ в АХ, а затем загрузить 0 в АХ:

Регистр АН является верхней 8-битной частью регистра АХ. После выполнения команды MOV ах, Ьх регистр АН будет содержать значение верхней части ре­ гистра ВХ, то есть значение регистра ВН. Но мы не можем быть уверены, что ВН содержит 0, поэтому мы должны загрузить 0 в АН — команда MOV ah, О «сбрасывает» значение регистра АН. В результате мы расширили 8-битное значение, ранее содержащееся в регистре BL, до 16 битов. Новое, 16-битное, значение будет находиться в регистре АХ.

Можно поступить и наоборот: сначала сбросить весь АХ, а затем загрузить BL в младшую часть АХ (AL):

Точно так же можно скопировать 16-битное значение в 32-битный регистр.

Для полноты картины приведем список всех допустимых форматов команды MOV — как в официальной документации:

M V r/m8,reg M V r/ml6,regl MOV r/m32,reg M Vregl6,r/ml M V reg32,r/m MOV reg8,imm M V regl6,imml M V reg32,imm MOV r/m8,imm MOV r/ml6,imml MOV r/m32,imm32 ' 4.2. «Остроконечники» и «тупоконечники»

Сейчас мы немного отклонимся от обсуждения команд. Предположим, что вы хотите проверить, было ли значение 0x12345678, которое содержалось в регистре ЕВР, корректно загружено в 32-разрядную переменную counter.

Следующий фрагмент кода заносит значение 0x12345678 в переменную co­ unter:

mov e b p, 0x12345678 ;загружаем в ЕВР значение 0x mov [ c o u n t e r ], ebp ;сохраняем значение ЕВР Для того чтобы проверить, загружено значение или нет, нужно воспользовать­ ся отладчиком. Понимаю, что вы пока не знаете ни того, как откомпилировать программу, ни того, как загрузить ее в отладчик, но давайте представим, что это уже сделано за вас.

Как будет выглядеть откомпилированная программа в отладчике? Отладчик преобразует все команды из машинного кода назад в язык ассемблера. Все точно так же, как мы написали, только с небольшим отличием: везде, где мы использовали символьное имя переменной, оно будет заменено реальным адресом переменной, например:

Первая колонка — это реальный адрес команды в памяти, вторая — машинный код, в который превратилась команда после компиляции. После этого мы ви­ дим символьное представление машинной команды в мнемокодах ассемблера.

Символическое имя нашей переменной counter было заменено адресом этой переменной в памяти (0х80490с0).

Перед выполнением первой команды, mov ebp, 0x12 345 67 8, регистры про­ цессора содержали следующие значения:

еах = 0x00000000 ebx = 0x00000000 есх = 0x00000000 edx = 0x esp = 0xBFFFF910 ebp = 0x00000000 e s i = 0x00000000 edi = 0x ds = 0x0000002B es = 0x0000002B fs = 0x00000000 gs = 0x ss = 0x0000002B cs = 0x00000023 eip = 0x0804808A eflags = 0x Flags: PF ZF TF IF ID После выполнения первой команды значение регистра ЕВР было заменено значением 0x12345678. Если просмотреть дамп памяти по адресу нашей пере­ менной (0х80490с0), то мы увидим следующее:

Dumping 64 b y t e s of memory s t a r t i n g at 0x080490C0 in hex 080490C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Ассемблер на примерах. Базовый курс Когда будет выполнена вторая команда MOV, значение 0x12345678 будет записано в память по адресу 0х80490с0 и дамп памяти покажет другой ре­ зультат:

Dumping 64 b y t e s of memory s t a r t i n g at 0x080490C0 in hex 080490C0: 78 56 34 12 00 00 00 00 00 00 00 00 00 00 00 00 xV Требуемое значение (0x12345678) действительно было записано по адресу 0х80490с0, но почему-то задом наперед. Дело в том, что все х86-процессоры от­ носятся к классу LITTLE_ENDIAN, то есть хранят байты слова или двойного слова в порядке от наименее значимого к наиболее значимому («little-end-first», младшим байтом вперед). Процессоры BIG_ENDIAN (например, Motorola) поступают наоборот: размещают наиболее значимый байт по меньшему адресу («big-end-first», старшим байтом вперед).

Любопытно, что термины LITTLEENDIAN и BIG_ENDIAN — это не просто сокращения:

они происходят от названий соперничавших в Лилипутии партий «остроконечников»

и «тупоконечников» из «Путешествий Гулливера» Джонатана Свифта, отсюда и название этого пункта. «Остроконечники» и «тупоконечники» у Свифта кушали яйца с разных концов, одни — с острого, другие — с тупого. В результате спора по поводу того, как правильнее, развязалась война, а дальше... если не помните, возьмите книжку и почитайте.

Порядок следования байтов в слове (двойном слове) учитывается не только при хранении, но и при передаче данных. Если у вас есть небольшой опыт программирования, возможно, вы сталкивались с «остроконечниками и тупоконечниками» при разработке сетевых приложений, когда некоторые структуры данных приходилось преобразовывать к «тупоконечному» виду при помощи специальных функций (htonl, htons, ntohl, ntohs).

Когда переменная counter будет прочитана обратно в регистр, там окажется оригинальное значение, то есть 0x12345678.

4.3. Арифметические команды Рассмотренная выше команда MOV относится к группе команд перемеще­ ния значений, другие команды из которой мы рассмотрим позже. А сейчас перейдем к следующей группе чаще всего используемых команд — арифме­ тическим операциям. Процессор 80386 не содержит математического сопро­ цессора, поэтому мы рассмотрим только целочисленную арифметику, которая полностью поддерживается процессором 80386. Каждая арифметическая команда изменяет регистр признаков.

4.3.1. Инструкции сложения ADD и вычитания SUB Начнем с самого простого — сложения (ADD) и вычитания (SUB). Команда ADD требует двух операндов, как и команда MOV:

Команда ADD складывает оба операнда и записывает результат в ol, предыдущее значение которого теряется. Точно так же работает команда вычитания — SUB:

Результат, ol-o2, будет сохранен в ol, исходное значение ol будет потеряно.

Теперь рассмотрим несколько примеров:

Поскольку мы хотим избежать уничтожения (то есть перезаписи результатом) исходных значений и хотим сохранить оба значения — АХ и СХ, мы копируем оригинальное значение СХ в DX, а затем добавляем АХ к DX. Команда ADD сохранит результат DX + АХ в регистре DX, а исходные значения АХ и СХ останутся нетронутыми.

Рассмотрим еще примеры использования инструкций ADD и SUB:

add b y t e [number] add dword [number], 4 добавляем значение Что произойдет, если сначала занести в AL (8-разрядный регистр) наибольшее допустимое значение (255), а затем добавить к нему 8?

В результате в регистре AL мы получим значение 7.

Ассемблер на примерах. Базовый курс Но мы ведь ожидали 0x107 (263 в десятичном виде). Что случилось? В регистре AL может поместиться только 8-разрядное число (максимальное значение — 255). Девятый, «потерянный», бит скрыт в регистре признаков, а именно в флаге CF — признак переноса. Признак переноса используется в арифметических командах при работе с большими диапазонами чисел, чем могут поддерживать регистры. Полезны для этого команды ADC (Add With Carry — сложение с переносом) и SBB (Subtract With Borrow — вычитание с займом):

Эти команды работают так же, как ADD и SUB, но соответственно добавляют или вычитают флаг переноса CF.

В контексте арифметических операций очень часто используются так называе­ мые пары регистров. Пара — это два регистра, использующихся для хранения одного числа. Часто используется пара EDX:EAX (или DX:AX) — обычно при умножении. Регистр АХ хранит младшие 16 битов числа, a DX — старшие битов. Таким способом даже древний 80286 может обрабатывать 32-разрядные числа, хотя у него нет ни одного 32-разрядного регистра.

Пример: пара DX:AX содержит значение OxFFFF (АХ = OxFFFF, DX = 0).

Добавим 8 к этой паре и запишем результат обратно в DX:AX:

Первая команда ADD добавит 8 к регистру АХ. Полностью результат не по­ мещается в АХ, поэтому его старший бит переходит в CF. Вторая команда добавит к DX значение 0 и значение CF.

После выполнения ADC флаг CF будет добавлен к DX (DX теперь равен 1).

Результат сложения OxFFFF и 8 (0x10007) будет помещен в пару DX:AX (DX=1,AX=0007).

Рис. 4.2. Сложение чисел OxFFFF и 0x0008 и их сохранение в регистрах Процессор 80386 может работать с 32-разрядными числами напрямую — безо всяких переносов:

Рис. 4.3. Использование 32-разрядных регистров процессора После выполнения этих инструкций в ЕАХ мы получим 32-разрядное значение 0x10007. Для работы с 64-разрядными числами мы можем использовать пару EDX:EAX — точно так же, как мы использовали пару DX:AX.

4.3.2. Команды инкрементирования INC Эти команды предназначены для инкрементирования и декрементирования.

Команда INC добавляет, a DEC вычитает единицу из единственного операнда.

Допустимые типы операнда — такие же, как у команд ADD и SUB, а формат команд таков:

DEC Ol ВНИМАНИЕ! Ни одна из этих инструкций не изменяет флаг CF. О значении этого факта и следствиях из него, а также о том, как безопасно (без потери Ассемблер на примерах. Базовый курс данных) использовать эти команды, будет сказано в главе, посвященной оптимизации.

Увеличение на единицу значения регистра AL выглядит следующим образом:

Увеличение на единицу значения 16-битной переменной number:

inc word [number] ;мы должны указать размер 4.3.3. Отрицательные числа — целые числа со знаком Отрицательные целые числа в ПК представлены в так называемом дополни­ тельном коде. Дополнительный код можно представить себе как отображение некоторого диапазона, включающего положительные и отрицательные целые числа, на другой диапазон, содержащий только положительные целые числа.

Рассмотрим код дополнения одного байта.

Один байт может содержать числа в диапазоне от 0 до 255. Код дополнения заменяет этот диапазон другим — от -128 до 127. Диапазон от 0 до 127 ото­ бражается сам на себя, а отрицательным числам сопоставляется диапазон от 128 до 255: числу -1 соответствует число 255 (OxFF), -2 — 254 (OxFE) и т.д.

Число -50 будет представлено как 206. Обратите внимание: самый старший бит отрицательного числа всегда устанавливается в 1 — так можно опреде­ лить, что число отрицательное. Процесс отображения отрицательных чисел в дополнительный код иногда называют маппингом (mapping).

Дополнительный код может быть расширен до 2 байтов (от 0 до 65535). Он будет охватывать диапазон чисел от -32768 до 32767. Если дополнительный код расширить до 4 байтов, то получим диапазон от -2 147 483 648 до 2 147 483 647.

Во многих языках программирования целочисленного типа данных (integer). 256(0x100) Пример: преобразуем числа 4, -4,386, -8000 206(0хСЕ) и 45000 в дополнительный код, считая, что целевой диапазон — 16 бит (2 байта).

Прежде всего, выясним, сколько чисел может поместиться в 16 разрядов. Это диапазон от -32 768 до 32 767 (0 — это положительное число!).

Первое число, 4, попадает в диапазон, поэтому оно отображается само на себя — в целевом диапазоне это будет тоже число 4. Число -4 — от­ рицательное, оно находится в диапазоне. В целевом диапазоне оно будет представлено как 65 536 — 4 = 65 532. Число 386 останется само собой. Число -8 000 — отрицательное, в результате отображения получается 65 536 — 8 000 = 57 536 — это и будет число -8 000 в дополнительном коде.

И, наконец, число 45 000 не может быть представлено в дополнительном коде, поскольку оно выходит за пределы диапазона.

Выполнять арифметические операции над отрицательными числами в допол­ нительном коде можно при помощи обычных команд ADD и SUB. Рассмотрим, как это происходит, на примере суммы чисел -6 и 7 в дополнительном коде из 2 байтов. Число 7 будет отображено само в себя, а число -6 будет представлено числом 65 536 — 6 = 65 530 (OxFFFA). Что получится, если мы сложим два эти числа (7 и 65 530)? Попробуем решить эту задачу на языке ассемблера:

Мы получим результат 65 530 + 7 = 65 537 = 0x10001, который не помещается в регистре АХ, поэтому будет установлен флаг переноса. Но если мы его про­ игнорируем, то оставшееся в АХ значение будет правильным результатом!

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

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

Результат: 0xFFF4 (установлен также флаг CF, но мы его игнорируем). В десятичной системе 0xFFF4 = 65 524. В дополнительном коде мы получим правильный результат:

-12 (65 536 — 65 524 = 12).

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

Пусть регистр ВХ содержит адрес, а нам нужен адрес предыдущего байта, но мы не хотим изменять значение регистра ВХ (предполагается, что процессор находится в реальном режиме):

mov а х, [ Ь х - 1 ] ;поместить в АХ значение по адресу Значение -1 будет преобразовано в OxFFFF, и инструкция будет выглядеть так: MOV AX, [BX+OxFFFF]. При вычислении адреса не учитывается флаг CF, поэтому мы получим адрес, на единицу меньший.

Ассемблер на примерах. Базовый курс Система команд процессора 80386 включает в себя несколько команд, предна­ значенных для работы с целыми числами со знаком. Первая из них — команда NEG (negation, отрицание):

NEG r/m NEG Г/Ш NEG Г/Ш Используя NEG, вы можете преобразовывать положительное целое число в отрицательное и наоборот. Инструкция NEG имеет только один операнд, который может быть регистром или адресом памяти. Размер операнда — лю­ бой: 8, 16 или 32 бита.

пед еах ;изменяет знак числа, сохраненного в ЕАХ пед b y t e [number] ;изменяет знак 8-битной переменной number Расширение диапазона целого беззнакового числа делалось просто: мы про­ сто копировали число в больший регистр, а расширенное «место» заполняли нулями. При работе с целыми числами со знаком мы должны заполнить это место старшим битом преобразуемого числа. Так мы можем сохранять поло­ жительные и отрицательные числа при расширении их диапазона. Расширение диапазона числа со знаком называется знаковым расширением.

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

Команда CBW копирует седьмой (старший) бит регистра AL в регистр АН, рас­ ширяя таким образом оригинальное значение регистра AL в значение со знаком регистра АХ (значение АН становится равно 0x00 или OxFF = 11111111b, в за­ висимости от старшего бита AL). Сложно? Ничего, скоро рассмотрим пару примеров, и все станет на свои места.

Рис. 4.5. Знаковое расширение с помощью инструкции CBW Команда CWD копирует старший бит АХ в регистр DX, расширяя таким об­ разом оригинальное значение АХ в пару регистров со знаком DX:AX.

Рис. 4.6. Знаковое расширение с помощью инструкции CWD Команда CDQ копирует старший бит ЕАХ в регистр EDX, расширяя таким об­ разом оригинальное значение ЕАХ в пару регистров со знаком EDX:EAX.

Команда CWDE копирует старший бит АХ в верхнюю часть (старшую часть) ЕАХ, расширяя таким образом оригинальное значение АХ в двойное слово со знаком, которое будет помещено в регистр ЕАХ.

Рис. 4.7. Знаковое расширение с помощью инструкции CWDE Рассмотрим пару примеров:

После выполнения команды CBW АХ будет содержать значение OxFFFF, то есть - 1. Единица (1) старшего разряда заполнила все биты АН, и мы получили знаковое расширение AL на весь регистр АХ.

Ассемблер на примерах. Базовый курс Первая команда заносит в регистр АХ значение 4. Вторая команда, CWD, производит знаковое расширение АХ в пару DX:AX. Оригинальное значение DX заменяется новым значением — старшим битом регистра АХ, который в этом случае равен 0. В результате мы получили 0 в регистре DX.

Иногда команда CWD полезна для очищения регистра DX, когда АХ содержит положительное значение, то есть значение, меньшее 0x8000.

4.3.5. Целочисленное умножение и деление Давайте познакомимся с оставшимися целочисленными операциями: умноже­ нием и делением. Первое арифметическое действие выполняется командой MUL, а второе — командой DIV.

Дополнительный код делает возможным сложение и вычитание целых чисел со знаком и без знака с помощью одних и тех же команд ADD и SUB. Но к умножению и делению это не относится: для умножения и деления чисел со знаком служат отдельные команды — IMUL и IDIV. Операнды этих инструк­ ций такие же, как у MUL и DIV.

Операции умножения и деления имеют свою специфику. В результате умно­ жения двух чисел мы можем получить число, диапазон которого будет в два раза превышать диапазон операндов. Деление целых чисел — это операция целочисленная, поэтому в результате образуются два значения: частное и остаток.

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

Подобно командам ADD и SUB, команды MUL, DIV, IMUL, IDIV изменяют регистр признаков.

Команда MUL может быть записана в трех различных форматах — в зави­ симости от операнда:

MUL r/m MUL r/ml MUL r/m В 8-разрядной форме операнд может быть любым 8-битным регистром или адресом памяти. Второй операнд всегда хранится в AL. Результат (произве­ дение) будет записан в регистр АХ.

(r/m8) * AL -> АХ В 16-разрядной форме операнд может быть любым 16-битным регистром или адресом памяти. Второй операнд всегда хранится в АХ. Результат сохраняется в паре DX:AX.

(r/ml6) * АХ -> DX:AX В 32-разрядной форме второй операнд находится в регистре ЕАХ, а результат записывается в пару EDX.EAX.

(r/m32) * ЕАХ -> EDX:ЕАХ Рассмотрим несколько примеров.

Пример 1: умножить значения, сохраненные в регистрах ВН и CL, результат сохранить в регистр АХ:

mov a l, bh ;AL = ВН — сначала заносим в AL второй операнд Результат будет сохранен в регистре АХ.

Пример: вычислить 4862, результат сохранить в DX:AX:

Пример 2: вычислить диаметр по радиусу, сохраненному в 8-битной перемен­ ной r a d i u s l, результат записать в 16-битную переменную d i a m e t e r l :

В 16-битной форме операнд может быть любым 16-битным регистром или адресом памяти. Второй операнд всегда находится в паре DX:AX. Результат сохраняется в паре DX:AX (DX — остаток, АХ — частное).

В 32-разрядной форме делимое находится в паре EDX:EAX, а результат за­ писывается в пару EDX:EAX (частное в ЕАХ, остаток в EDX).

Команда IDIV используется для деления чисел со знаком, синтаксис ее такой же, как у команды DIV.

Рассмотрим несколько примеров.

Пример 1: разделить 13 на 2, частное сохранить в BL, а остаток в — ВН:

mov bx,ax ожидаемый результат находится в АХ, Пример 2:

-вычислить радиус по диаметру, значение которого сохранено в 16-битной переменной diameterl, результат записать в radiusl, а остаток проигнорировать.

К логическим операциям относятся: логическое умножение (И, AND), логи­ ческое сложение (ИЛИ, OR), исключающее ИЛИ (XOR) и отрицание (NOT).

Все эти инструкции изменяют регистр признаков.

Команда AND выполняет логическое умножение двух операндов — ol и о2.

Результат сохраняется в операнде ol. Типы операндов такие же, как у коман­ ды ADD: операнды могут быть 8-, 16- или 32-битными регистрами, адресами памяти или непосредственными значениями.

Таблица истинности для оператора AND приведена ниже (табл. 4.1).

Следующий пример вычисляет логическое И логической единицы и логиче­ ского нуля (1 AND 0).

Тот же самый пример, но записанный более компактно:

Ассемблер на примерах. Базовый курс Команда OR выполняет логическое сложение двух операндов — ol и о2.

Результат сохраняется в операнде ol. Типы операндов такие же, как у ко­ манды AND.

Таблица истинности для оператора OR приведена ниже (табл. 4.2).

Дополнительные примеры использования логических команд будут приведены в последнем пункте данной главы. А пока рассмотрим простой пример уста­ новки наименее значимого бита (первый справа) переменной mask в 1.

or byte [mask], Вычисляет так называемое «исключающее ИЛИ» операндов ol и о2. Результат сохраняется в о1. Типы операндов такие же, как у предыдущих инструкций.

Формат команды:

Таблица истинности для оператора XOR приведена ниже (табл. 4.3).

Исключающее ИЛИ обратимо: выражение ((х хог у) хог у) снова возвра­ тит х.

xor al,0xAA ;возвращаем в AL исходное значение - 0x Используется для инверсии отдельных битов единственного операнда, ко­ торый может быть регистром или памятью. Соответственно команда может быть записана в трех различных форматах:

NOT r/m NOT r/ml NOT r/m Таблица истинности для оператора NOT приведена ниже (табл. 4.4).

Следующий пример демонстрирует различие между операциями N O T и NEG:

Любое число можно записать в двоичной системе в виде последовательности нулей и единиц. Например, любое 16-разрядное число состоит из 16 двоичных цифр — 0 и 1. Мы можем использовать одно число для хранения шестнадцати различных состояний — флагов. Нам не нужно тратить место на хранение различных переменных, ведь для описания состояния (включено/выключено) вполне достаточно 1 бита. Переменная, используемая для хранения флагов, называется разрядной матрицей или массивом битов.

Высокоуровневые языки программирования также используют разрядные матрицы, например, при хранении набора значений перечисления, для эко­ номии памяти. Мы уже знакомы с одной разрядной матрицей, которая очень часто используется в программировании — это регистр признаков микропро­ цессора. Мы будем очень часто сталкиваться с разрядными матрицами при программировании различных устройств: видеоадаптера, звуковой платы и т.д.

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

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

Для установки определенных битов массива в единицу (все остальные биты при этом должны остаться без изменения) применяется команда OR. В каче­ стве маски возьмите двоичное число, в котором единицы стоят на месте тех битов, которые вы хотите установить в массиве. Например, если вы хотите установить первый и последний биты массива, вы должны использовать ма­ ску 10000001. Все остальные биты останутся нетронутыми, поскольку 0 OR X всегда возвращает X.

Чтобы сбросить некоторые биты (установить их значение в 0), возьмите в качестве маски число, в котором нули стоят на месте тех битов, которые вы хотите сбросить, а единицы — во всех остальных позициях, а потом исполь­ зуйте команду AND. Поскольку 1 AND X всегда возвращает X, мы сбросим только необходимые нам биты.

Рассмотрим несколько примеров.

Пример. В регистре AL загружен массив битов. Нужно установить все не­ четные позиции в 1. Предыдущее состояние массива неизвестно.

or a l, 10101010b ;маска устанавливает все нечетные биты в Пример. В массиве битов, хранящемся в регистре AL, сбросить 0-й и 7-й биты, все остальные оставить без изменения. Исходное состояние массива также неизвестно.

and a l, 01111110b ;каждая 1 в маске сохраняет бит С помощью XOR также можно изменять значения битов, не зная предыдуще­ го состояния. Для этого в маске установите 1 для каждого бита, который вы хотите инвертировать (0 станет 1, а 1 станет 0), а для всех оставшихся битов установите 0. Если мы выполним XOR дважды, то получим исходное значение.

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

Управляющие конструкции Последовательное выполнение команд Конструкция «IF THEN»

Итерационные конструкции — циклы Команды обработки стека Ассемблер на примерах.

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

5.1. Последовательное выполнение команд Последовательная обработка знакома нам еще с концепции фон Неймана.

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

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

Если программа не содержит других конструкций, кроме последовательности элементарных команд, она называется линейной.

Рис. 5.1. Последовательная обработка команд 5.2. Конструкция «IF THEN» — выбор пути В языках программирования высокого уровня конструкция выбора извест­ на как оператор IF-THEN. Эта конструкция позволяет выбрать следующее действие из нескольких возможных вариантов в зависимости от выполнения определенного условия. В языке ассемблера механизм выбора реализован посрздством команд сравнения, условного и безусловного переходов.

Команды СМР и TEST используются для сравнения двух операндов. Операн­ дами могут быть как регистры, так и адреса памяти, размер операнда — 8, 16 или 32 бита.

Команда СМР — это сокращение от «compare», «сравнить». Она работает подобно SUB: операнд о2 вычитается из ol. Результат нигде не сохраняется, команда просто изменяет регистр признаков. Команда СМР может исполь­ зоваться как для сравнения целых беззнаковых чисел, так и для сравнения чисел со знаком.

Команда TEST работает подобно СМР, но вместо вычитания она вычисля­ ет поразрядное И операндов. Результат инструкции — измененные флаги регистра признаков. Мы можем использовать TEST для проверки значений отдельных битов в массиве битов.

Проиллюстрируем эти команды несколькими примерами:

стр [ d i a m e t e r l ],ах,-сравниваем переменную " d i a m e t e r l " с АХ Ассемблер на примерах. Базовый курс t e s t ax, 00000100b,-проверяем значение второго 5.2.2. Команда безусловного перехода — JMP Самый простой способ изменить последовательность выполнения команд заключается в использовании команды jmp — так называемой команды без­ условного перехода. Она перезаписывает указатель команд (регистр IP или CS), что заставляет процессор «переключиться» на выполнение команды по указанному адресу. Формат команды таков:

JMP [тип_перехода] операнд Команда JMP — аналог конструкции GOTO, которая используется в высо­ коуровневых языках программирования. Название команды объясняет ее действие, а именно «jump», «переход». Команде нужно передать один обяза­ тельный операнд — адрес в памяти, с которого процессор должен продолжить выполнение программы. Операнд может быть указан явно (непосредственное значение адреса) или быть регистром общего назначения, в который загружен требуемый адрес. Но новичкам я никогда не рекомендовал бы это делать: язык ассемблера, подобно языкам программирования высокого уровня, позволяет обозначить адрес назначения при помощи метки.

В зависимости от «расстояния» переходы бывают трех типов: короткие (short), ближние (near) и дальние (far). Тип перехода задается необязательным параметром инструкции jmp. Если тип не задан, по умолчанию используется тип near.

Максимальная «длина» короткого перехода (то есть максимальное расстояние между текущим и целевым адресом) ограничена. Второй байт инструкции (операнд) содержит только одно 8-разрядное значение, поэтому целевой адрес может быть в пределах от -128 до 127 байтов. При переходе выполняется знаковое расширение 8-разрядного значения и его добавление к текущему значению Е(IР).

«Длина» ближнего перехода (near) зависит только от режима процессора. В реальном режиме меняется только значение IP, поэтому мы можем «путеше­ ствовать» только в пределах одного сегмента (то есть в пределах 64 Кб); в защищенном режиме используется EIP, поэтому целевой адрес может быть где угодно в пределах 4 Гб адресного пространства.

Переход типа far модифицирует кроме IP еще и сегментный регистр CS, ко­ торый используется при вычислении фактического адреса памяти. Поэтому команда перехода должна содержать новое значение CS.

Сейчас мы совершим «дальний переход» от предмета нашего рассмотрения и поговорим о метках в языке ассемблера. Вкратце, метка — это идентифика­ тор, заканчивающийся двоеточием. Во время компиляции он будет заменен точным адресом согласно его позиции в программе. Рассмотрим следующий фрагмент кода:

Чтобы перейти к метке newloop из другого места программы, используйте команду:

jmp new_loop ;переходим к new_loop После выполнения этой команды выполнение программы продолжится с метки new_loop.

Если вам нужно сначала написать инструкцию перехода и только потом определить метку, нет проблем: компилятор обрабатывает текст программы в несколько проходов и понимает такие «забегания вперед»:

Теперь давайте вернемся к различным типам переходов: даже если мы нович­ ки, мы все равно будем изредка их использовать. Короткий переход полезен в ситуации, где метка назначения находится в пределах 128 байтов. Поскольку команда короткого перехода занимает 2 байта, команда ближнего перехода занимает 3 байта, а дальнего — 5 байтов, мы можем сэкономить байт или три.

Если вы не можете оценить правильное «расстояние», все равно можете по­ пробовать указать s h o r t — в крайнем случае, компилятор выдаст ошибку:

jmp short near_label /переходим к "near_label" Другой способ изменения последовательности выполнения команд заключа­ ется в использовании команды условного перехода.

В языке ассемблера имеется множество команд условного перехода, и боль­ шинство из них вам нужно знать — иначе вы не сможете написать даже Ассемблер на примерах. Базовый курс «средненькую» программку. Имена этих команд различаются в зависимости от условия перехода. Условие состоит из значений одного или нескольких флагов в регистре признаков. Работают эти команды одинаково: если условие истинно, выполняется переход на указанную метку, если нет, то процессор продолжит выполнять программу со следующей команды.

Общий формат команд условного перехода следующий:

Jx метка_назначения Рассмотрим наиболее часто встречающиеся команды:

Любое условие может быть инвертировано, например:

jnz is_true ;переходит к is_true, если флаг ZF = О Так же образованы имена команд JNC, JNS и JNO.

Рассмотрим сводную таблицу команд условного перехода в зависимости от условия, которое проверяет процессор (чтобы не писать «для перехода», будем использовать сокращение jump) (см. табл. 5.1).

беззнаковых Инструкции Jump, Jump, если для чисел если равно не равно В первой строке таблицы указано условие перехода. Во второй строке по­ казаны соответствующие команды условного перехода (в скобках — их до­ полнительные названия). Чтобы лучше запомнить имена команд, запомните несколько английских слов: equal — равно, above — больше, below — ниже, zero — ноль, greater — больше, less — меньше. Таким образом, JE — Jump if Equal (Переход, если Равно), JNE — Jump if Not Equal (Переход, если Не Равно), JA — Jump if Above (Переход, если больше) и т.д.

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

Адрес назначения команды условного перехода должен лежать в пределах 128 байтов: все они реализуют переходы короткого типа. Если вам нужно «прогуляться» за пределы 128 байтов, то вы должны в инструкции условного перехода указать адрес, по которому будет находиться команда jmp, которая и выполнит дальнейший переход:

far_jump:

Теперь рассмотрим, как реализовать конструкцию IF-THEN на языке ассем­ блера. В нашем простом случае мы перейдем к метке i f_three, если регистр АХ содержит значение 3.

Прежде всего мы должны проверить, есть ли в регистре АХ тройка. Для этого используем команду СМР:

Для проверки равенства применим команду JZ, как показано в таблице ко­ манд условного перехода:

Обратите внимание, что для проверки на равенство используются одина­ ковые команды (JZ — равно и JNZ — не равно) для чисел со знаком и для беззнаковых чисел. Если АХ = 3, то команда jz выполнит переход к метке i s _ t h r e e, в противном случае будет продолжено выполнение программы со следующей за jz команды.

Следующий пример показывает беззнаковое сравнение CL и AL. Если оба значения равны, то в регистр BL помещается значение 1, если AL больше, чем CL, то BL=2, а если AL меньше CL, то BL=3.

Ассемблер на примерах. Базовый курс В нашей программе мы использовали безусловный переход (jmp end_if), что­ бы вернуть управление на исходную позицию. Это не лучшее решение: нам придется выполнить еще один безусловный переход перед меткой w r i t e _ l, а то наша программа «зациклится». Адрес назначения понятен — следую­ щая после последнего jmp end_if команда. Вот так выглядит улучшенный фрагмент кода:

ja end_if ;переходим в конец программы, если AL > CL Новый пример короче, но нет предела совершенству, и мы можем его еще улучшить. Инструкция MOV не изменяет регистр флагов, поэтому в дальней­ шем сравнении нет надобности:

ja end_if Если подытожить, то мы только что записали на Ассемблере следующую конструкцию языка С:

5.3. Итерационные конструкции — циклы Последней управляющей конструкцией, которую мы рассмотрим, будет итера­ ция, или цикл. Циклом называется многократное повторение последователь­ ности команд до наступления указанного условия.

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

• цикл со счетчиком (цикл FOR), повторяющийся заранее заданное ко­ личество раз;

• цикл с условием (цикл WHILE), повторяющийся до тех пор, пока условие истинно;

• цикл с инверсным условием (цикл UNTIL), повторяющийся до тех пор, пока условие не станет истинным.

Цикл со счетчиком с помощью конструкций IF и GOTO Давайте попробуем написать цикл с пустым телом (то есть внутри цикла не будут выполняться никакие команды). Первое, с чем нужно разобраться — это где разместить переменную управления циклом, то есть счетчик. Счетчик нужен для того, чтобы цикл выполнялся не бесконечно, а определенное ко­ личество раз. Команда сравнения позволяет хранить счетчик либо в памяти, либо в каком-то регистре общего назначения.

Ассемблер на примерах. Базовый курс Рассмотрим символическую структуру пустого цикла FOR на псевдоязыке:

1=1+ IF I < 10 THEN

GOTO FOR_LOOP

В нашем примере тело цикла должно повторяться 10 раз. Сначала мы ини­ циализируем счетчик. Затем выполняем тело цикла (в нашем случае пустое), после этого увеличиваем счетчик на 1. Проверяем: если счетчик меньше 10, то начинаем опять выполнять тело цикла, если же счетчик равен 10, то мы выходим из цикла.

А теперь запишем нашу схему на языке ассемблера. Мы уже знаем, как ре­ ализовать на языке ассемблера конструкции IF и GOTO, из которых можно построить цикл FOR. В качестве счетчика (псевдопеременной I) мы будем использовать регистр ЕСХ:

for_start:

mov ecx, for_loop:

for_finish: ;если ЕСХ = 10, выходим Рассмотрим другую версию цикла FOR. Она работает так же, как предыдущая, но счетчик мы будем хранить не в регистре, а в памяти, в переменной I.

for_start:

mov dword [i],0 ;переменная типа dword 1 = cmp dword [ i ], 1 0,-сравниваем i с Вторая версия будет работать медленнее, поскольку счетчик хранится в памяти, время доступа к которой существенно больше, чем время доступа к регистрам.

В заключение давайте рассмотрим еще одну версию цикла, использующую команду DEC и команду проверки флага ZF вместо команды сравнения СМР.

Принцип работы следующий: устанавливаем счетчик (ЕСХ=10), выполняем тело цикла, уменьшаем счетчик на 1. Если ZF установлен, значит, в ЕСХ на­ ходится 0 и нам нужно прекратить выполнение цикла:

for_start:

Мы только что записали на языке ассемблера следующую конструкцию языка С:

LOOP — сложная команда, простая запись цикла В главе, посвященной процессору 80386, мы упомянули, что х86-совместимые чипы используют архитектуру CISC (Компьютер со сложным набором команд), то есть имеют полную систему команд. Другими словами, в составе системы команд имеются сложные команды, которые могут заменить ряд простых. При чем здесь циклы? Если у вас CISC-процессор, то вам не нужно Другая команда, POP, записывает в свой операнд значение вершины стека (последнее сохраненное в стеке значение). Тип операнда должен быть таким же, как у инструкции PUSH (другими словами, если вы поместили в стек 32-разрядный регистр, извлечение из стека должно происходить тоже в 32разрядный регистр).

Команду POP можно реализовать с помощью команд MOV и ADD:

Рассмотрим несколько примеров:

В результате выполнения этих команд мы поменяем местами значение реги­ стров ЕАХ и ESI: сначала помещаем в стек значение ЕАХ, затем — ESI, после этого извлекаем из стека последнее сохраненное значение (бывшее значение регистра ESI) в регистр ЕАХ, после этого в стеке останется бывшее значение ЕАХ, которое мы записываем в ESI.

Для обеспечения обратной совместимости с процессорами предыдущих по­ колений 16-битные регистры тоже можно поместить в стек.

Ассемблер на примерах. Базовый курс До выполнения первой команды PUSH вершина стека содержала значение 0x0000. На вершину стека указывает пара SS:SP. Допустим, что SP содержит адрес OxFFFE. После выполнения PUSH AX указатель стека был уменьшен на 2 и принял значение OxFFFC, и по этому адресу (в новую вершину стека) было записано значение 0x1234. Вторая команда, PUSH BX, также уменьши­ ла значение SP на 2 (OxFFFA) и записала в новую вершину стека значение 0x5678. Команда POP BX удалила значение 0x5678 из стека и сохранила его в регистре ВХ, а указатель стека увеличила на 2. Он стал равен OxFFFC, и в вершине стека оказалось значение 0x1234.

Помните, что 8-битные регистры сохранять в стеке нельзя. Нельзя и поместить в стек регистр IP (EIP) непосредственно, при помощи команд PUSH/POP: это делается по-другому, и чуть позже вы узнаете, как именно.

«толкаем» все регистры общего назначения Иногда полезно сохранить в стеке значения сразу всех регистров общего на­ значения. Для этого используется команда PUSHA, а для извлечения из стека значений всех регистров служит команда РОРА. Команды PUSHA и РОРА помещают в стек и извлекают из него все 16-разрядные регистры. Операндов у этих команд нет.

Поскольку команды PUSHA и РОРА разрабатывались для предшественника процессора 80386, они не могут сохранять значений 32-битных регистров (они просто не подозревают об их существовании). Для сохранения и восстановле­ ния значений расширенных регистров служат команды PUSHAD и POPAD.

Регистры помещаются в стек в следующем порядке (сверху вниз):

(Е)АХ, (Е)СХ, (E)DX, (E)BX, (E)SP, (E)BP, (E)SI, (E)DI Рассмотрим небольшой пример:

pusha ;поместить в стек все регистры общего назначения ;некоторые действия, модифицирующие рора ;восстанавливаем все регистры Рассмотренные четыре команды не заботились о помещении в стек регистра признаков. В 16-битных процессорах и регистр признаков был 16-битным, по­ этому для помещения в стек флагов и восстановления из него использовались команды PUSHF и POPF. Для новых процессоров, где регистр признаков 32-битный, нужно использовать 32-битные версии этих команд — PUSHFD и POPFD.

Ни одна из рассмотренных до сих пор операций не изменяет старшие 16 битов регистра флагов, поэтому для практических целей будет достаточно команд PUSHF и POPF.

pushf ;помещаем результат сравнения в стек... ;выполняем операции, изменяющие флаги add d i, 4 ;например, сложение jz equal ;если АХ = ВХ, переходим на "equal" Команды CALL и RET: организуем подпрограмму Ни одна серьезная программа не обходится без подпрограмм. Основное на­ значение подпрограмм — сокращение кода основной программы: одни и те же инструкции не нужно писать несколько раз — их можно объединить в подпрограммы и вызывать по мере необходимости.

Для вызова подпрограммы используется команда CALL, а для возврата из подпрограммы в основную программу — RET. Формат обеих команд таков:

CALL тип_вызова операнды Команде CALL нужно передать всего один операнд — адрес начала подпро­ граммы. Это может быть непосредственное значение, содержимое регистра, памяти или метка. В отличие от JMP, при выполнении команды CALL первым Ассемблер на примерах. Базовый курс делом сохраняется в стеке значение регистра IP (EIP). Передача управления на указанный адрес называется вызовом подпрограммы.

Как и команде JMP, команде CALL можно указать «размер шага». По умол­ чанию используется near. Когда происходит вызов типа f a r, сегментный регистр CS также сохраняется в стеке вместе с IP (EIP).

Возврат из подпрограммы выполняется с помощью команды RET, которая выталкивает из стека его вершину в IP (EIP). После этого процессор про­ должит выполнение инструкций, находящихся в основной программе после команды CALL.

Если подпрограмма вызывалась по команде CALL far, то для возврата из нее нужно восстановить не только IP (EIP), но и CS: следует использовать команду RETF, а не RET.

Существует еще более сложный способ возврата из подпрограммы: команда RETF или RET может принимать непосредственный операнд, указывающий, сколько порций данных нужно вытолкнуть из стека вслед за IP (EIP) и CS.

Этот вариант мы рассмотрим в 13 главе, когда будем говорить об объедине­ нии в одной программе фрагментов кода на ассемблере и на языках высокого уровня, а сейчас перейдем к практике.

Напишем подпрограмму, которая складывает значения ЕАХ и ЕВХ, а ре­ зультат помещает в ЕСХ, не обращая внимания на переполнение. Значения ЕАХ и ЕВХ после возвращения из подпрограммы должны сохраниться не­ изменными.

Назовем нашу подпрограмму a d d _ i t. Прежде всего мы должны получить аргументы из основной программы. В высокоуровневых языках для передачи аргументов используется стек, но мы упростим себе задачу и используем ре­ гистры. Операция ADD изменяет значение своего операнда, поэтому первым делом сохраним его в стеке:

add_it:

push eax ;сохраняем значение ЕАХ в стек mov ecx,eax /копируем значение из ЕАХ в ЕСХ pop eax ;восстанавливаем оригинальное значение ЕАХ Теперь вызовем нашу подпрограмму add_it с аргументами 4 и 8:

call add it ;вызываем add_it Что если мы забудем восстановить оригинальное значение ЕАХ (забудем написать команду pop eax)? Команда RET попыталась бы передать управлеГлава 5. Управляющие конструкции ние адресу, заданному оригинальным значением ЕАХ, что могло бы вызвать сбой нашей программы, а то и всей операционной системы. То же самое произойдет, если мы забудем написать команду RET: процессор продолжит выполнение с того места, где заканчивается наша подпрограмма, и рано или поздно совершит недопустимое действие.

Мы можем упростить нашу подпрограмму a d d _ i t, полностью отказавшись от инструкций POP и PUSH:

add_it:

mov e c x, e a x ;копируем значение ЕАХ (первый параметр) в ЕСХ Вернемся к теме прерываний. Прерыванием называется такое событие, когда процессор приостанавливает нормальное выполнение программы и начинает выполнять другую программу, предназначенную для обработки прерывания.

Закончив обработку прерывания, он возвращается к выполнению приоста­ новленной программы.

Во второй главе было сказано, что все прерывания делятся на две группы:

программные и аппаратные. Программные прерывания порождаются по ко­ манде INT. Программные прерывания можно рассматривать как «прерывания по требованию», например, когда вы вызываете подпрограмму операционной системы для вывода строки символов. В случае с программным прерыванием вы сами определяете, какое прерывание будет вызвано в тот или иной момент.

Команде INT нужно передать всего один 8-битный операнд, который задает номер нужного прерывания.

Аппаратные прерывания вызываются аппаратными средствами компьютера, подключенными к общей шине (ISA или PCI). Устройство, запрашивающее прерывание, генерирует так называемый запрос на прерывание (IRQ, interrupt requests). Всего существует 16 аппаратных запросов на прерывание, поскольку только 16 проводников в шине ISA выделено для этой цели. Запрос на пре­ рывание направляется контроллеру прерываний, который, в свою очередь, за­ прашивает микропроцессор. Вместе с запросом он передает процессору номер прерывания. После запуска компьютера и загрузки операционной системы DOS, IRQ 0 (системный таймер) соответствует прерыванию 8 (часы).

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

Роль закладки играют значения CS, (Е)1Р и регистр флагов.

Ассемблер на примерах. Базовый курс Теперь процессор будет выполнять другую программу — обработчик пре­ рывания. Адрес этой программы называется вектором прерывания. Векторы прерывания хранятся в таблице векторов прерываний, находящейся в памяти.

Таблицу прерываний можно представить себе как массив адресов подпро­ грамм, в котором индекс массива соответствует номеру прерывания.



Pages:     || 2 | 3 | 4 |


Похожие работы:

«*ISSN 1406-3360 № 1015 августа 2002 г.№ 10 I Ст.116. Постановление Правительства Республики от 25 января 2002 г. No 56 Государственная программа обучения для основной школы и гимназии 437 1 ГОСУДАРСТВЕННАЯ ПРОГРАММА ОБУЧЕНИЯ ДЛЯ ОСНОВНОЙ ШКОЛЫ И ГИМНАЗИИ Глава 1. Общие положения Глава 2. Общая часть Глава 3. Прикладные положения EESTI KEEL (eesti ppekeelega phikoolile) 1. peatkk ldalused. 2. peatkk Eesti keele ainekava 1.—3. klassile. 3. peatkk Eesti keele ainekava 4.—6. klassile. 4. peatkk...»

«Аннотация дисциплины Организационные и научно-методологические основы стандартизации, сертификации, менеджмента качества продукции и услуг специальность 05.02.23 – Стандартизация и управление качеством продукции Общая трудоемкость изучения дисциплины составляет 10 ЗЕД (360 час). Форма обучения: очная и заочная. Рабочая программа дисциплины Организационные и научно-методологические основы стандартизации, сертификации, менеджмента качества продукции и услуг составлена на основании федеральных...»

«Приложение 5: Рабочая программа специальной дисциплины История русской литературы ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ ПЯТИГОРСКИЙ ГОСУДАРСТВЕННЫЙ ЛИНГВИСТИЧЕСКИЙ УНИВЕРСИТЕТ Утверждаю Проректор по научной работе и развитию интеллектуального потенциала университета профессор З.А. Заврумов _2013 г. Аспирантура по специальности 10.01.01 Русская литература отрасль науки: 10.00.00 Филологические науки Кафедра отечественной и...»

«Балаковский инженерно-технологический институт филиал федерального государственного автономного образовательного учреждения высшего профессионального образования Национальный исследовательский ядерный университет МИФИ Кафедра Подъемно-транспортные, строительные и дорожные машины РАБОЧАЯ ПРОГРАММА по дисциплине ДС.12.07.4 САПР дорожно-коммунальных машин специальности 190205.65 Подъемно-транспортные, строительные, дорожные машины и оборудование форма обучения – очная курс – 5 семестр – 9 зачетных...»

«ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ НАУЧНОЕ УЧРЕЖДЕНИЕ ИНСТИТУТ ХУДОЖЕСТВЕННОГО ОБРАЗОВАНИЯ РОССИЙСКОЙ АКАДЕМИИ ОБРАЗОВАНИЯ Лаборатория интеграции искусств с проблемной группой театра и экранных искусств УТВЕРЖДАЮ Директор ФГНУ ИХО РАО _Л.В. Школяр 20 г. РАБОЧАЯ ПРОГРАММА ПО ДИСЦИПЛИНЕ ПСИХОЛОГИЯ ИСКУССТВА ОД.А.06 для аспирантов очной и заочной форм обучения, обучающимся по педагогическим наукам Москва Составитель: Кандидат искусствоведения Е.Н. Пирязева Рецензент: Доктор философских наук С.М. Оленев...»

«Государственное образовательное учреждение среднего профессионального образования города Москвы спортивно-педагогический Колледж Департамента физической культуры и спорта города Москвы УТВЕРЖДАЮ Директор ГОУ Спортивнопедагогический колледж Москомспорта А.В. Жмулин _ 20г. РАБОЧАЯ ПРОГРАММА УЧЕБНОЙ ДИСЦИПЛИНЫ МЕНЕДЖМЕНТ В СФЕРЕ ОБРАЗОВАТЕЛЬНЫХ УСЛУГ Специальность - 050720. 52 физическая культура Квалификация - учитель физической культуры Форма обучения – очная Москва - Одобрена кафедрой...»

«УДК 378.416 Н.Н. Елистратова ЭЛЕКТРОННЫЙ УЧЕБНИК КАК СРЕДСТВО И УСЛОВИЕ МУЛЬТИМЕДИЙНОГО ОБУЧЕНИЯ В ПЕДАГОГИКЕ ВЫСШЕЙ ШКОЛЫ Статья посвящена проблемам использования электронных учебников как основы мультимедийного обучения в вузе. Рассмотрены виды электронных учебников, их структура и содержание, особенности педагогического воздействия на обучаемых в процессе применения в образовательном процессе вуза, преимущество компьютерного обучения по сравнению с традиционным, а также негативные стороны...»

«Администрация города Иркутска Комитет по экономике ОРГАНИЗАЦИОННЫЙ СПРАВОЧНИК Информационно-справочное пособие Иркутск 2012 УДК 336 1 ББК 65.29 Администрация г.Иркутска Комитет по экономике Руководители разработки: Заместитель мэра - председатель комитета по Альмухамедов А. А. экономике администрации г. Иркутска Заместитель председателя комитета – начальник Евладов А. С. департамента предпринимательства и развития потребительского рынка комитета по экономике администрации г. Иркутска Начальник...»

«МИНИСТЕРСТВО СЕЛЬСКОГО ХОЗЯЙСТВА РОССИЙСКОЙ ФЕДЕРАЦИИ Федеральное государственное образовательное учреждение профессионального высшего образования КУБАНСКИЙ ГОСУДАРСТВЕННЫЙ АГРАРНЫЙ УНИВЕРСИТЕТ УТВЕРЖДАЮ Декан факультета плодоовощеводства и виноградарства доцент Горлов С.М. _2010 г. РАБОЧАЯ ПРОГРАММА дисциплины Экономика ДЛЯ СПЕЦИАЛЬНОСТИ: 110202.65 – Плодоовощеводство и виноградарство Факультет плодоовощеводства и виноградарства Ведущая кафедра – Экономическая теория Вид учебной работы Дневная...»

«Санкт-Петербургский государственный политехнический университет УТВЕРЖДАЮ Декан ФМФ В.К. Иванов _ _ _ г. РАБОЧАЯ ПРОГРАММА УЧЕБНОЙ ДИСЦИПЛИНЫ Основы прикладной статистики Кафедра-разработчик Биофизика Направление (специальность) подготовки 011200 Физика Наименование ООП Квалификация (степень) выпускника Бакалавр Образовательный стандарт Федеральный ГОС Форма обучения очная Соответствует ФГОС ВПО. Утверждена протоколом заседания кафедры Биофизика № 2 от 17.05. Программу в соответствии с ФГОС ВПО...»

«Приложение Протокольного решения Правительства РА N32 от 9 августа 2012г. ТРЕТИЙ ДОКЛАД РЕСПУБЛИКИ АРМЕНИЯ СОГЛАСНО СТАТЬИ 15-ОЙ ПУНКТА 1-ГО ЕВРОПЕЙСКОЙ ХАРТИИ РЕГИОНАЛЬНЫХ ЯЗЫКОВ ИЛИ ЯЗЫКОВ МЕНЬШИНСТВ Ереван 2012 Содержание Введение Часть 1 Анализ ситуации Часть 2 Практические шаги, осуществленные на национальном уровне, по подведению итогов второго этапа мониторинга по выполнению Европейской Хартии региональных языков или языков меньшинств Часть 3 Осуществленные программы и предпринятые меры...»

«Новосибирская государственная академия водного транспорта Шифр дисциплины: Технология и организация перегрузочных работ Рабочая программа по специальности 240100 Организация перевозок и управление на транспорте (водном) Новосибирск 2001 2 Рабочая программа составлена на основании Государственного образовательного стандарта высшего профессионального образования: государственные требования к минимуму содержания и уровню подготовки выпускников по специальности 240100 Организация перевозок и...»

«11 сентября 2009 года Информационный №27 бюллетень (567) Издание зарегистрировано в Минпечати РФ, свидетельство Эл. №77 8295 от 23.09.2003 В НОМЕРЕ В ЦЕНТРЕ ВНИМАНИЯ В Минкомсвязи состоялось заседание Совета по телевидению.......................................................3 Глава Минкомсвязи вошел в состав Комиссии Российской Федерации по делам ЮНЕСКО................................ Вниманию руководителей...»

«1 МИНИСТЕРСТВО СЕЛЬСКОГО ХОЗЯЙСТВА РОССИЙСКОЙ ФЕДЕРАЦИИ Федеральное государственное бюджетное образовательное учреждение высшего профессионального образования КУБАНСКИЙ ГОСУДАРСТВЕННЫЙ АГРАРНЫЙ УНИВЕРСИТЕТ УТВЕРЖДАЮ декан факультетов защиты растений, агрохимии и почвоведения. доцент Лебедовский И.А. _ _ 2013 г. РАБОЧАЯ ПРОГРАММА ДИСЦИПЛИНЫ Биологическая защита растений Бакалавры 110400. 62 Агрономия Форма обучения очная Вид учебной работы Дневная форма обучения Часов/з.е. Курс, семестр...»

«ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ Государственное образовательное учреждение высшего профессионального образования Уральский государственный университет им. А.М. Горького ИНСТИТУТ УПРАВЛЕНИЯ И ПРЕДПРИНИМАТЕЛЬСТВА КАФЕДРА ТЕОРИИ УПРАВЛЕНИЯ И ИННОВАЦИЙ ТЕОРЕТИЧЕСКИЕ ОСНОВЫ РЕСТРУКТУРИЗАЦИИ Программа дисциплины Стандарт ПД-СД ЕКАТЕРИНБУРГ 2009 2 I. ВВЕДЕНИЕ На этапе становления и развития рыночной экономики России научная дисциплина Антикризисное управление базировалась исключительно на...»

«Московский государственный университет имени М.В.Ломоносова Географический факультет Утверждено академик РАН Н.С.Касимов __ 20г. ПРОГРАММА УЧЕБНОЙ ДИСЦИПЛИНЫ Наименование дисциплины Ландшафтное планирование по направлению подготовки 021000 География уровня подготовки высшего профессионального образования интегрированный магистр с присвоением квалификации (степени) магистр 1. Цели и задачи освоения дисциплины Целями освоения дисциплины является: • приобретение знаний о принципах адаптации...»

«МежгоСударСтвенный фонд гуМанитарного СотрудничеСтва гоСударСтв – учаСтников Снг Санкт-ПетербургСкий гоСударСтвенный универСитет факультет филологии и иСкуССтв СИНТАКСИС СОВРЕМЕННОГО РУССКОГО ЯЗЫКА Учебник для филологических специальностей университетов СНГ Санкт-Петербург 2008 ббк 81.2рус-2 C38 авторы: Г. Н. Акимова (изменения в синтаксическом строе); С. В. Вяткина (введение, Предложение: основные понятия — § 1, 2 (совместно с в. П. казаковым), § 3, двусоставные предложения — § 1,...»

«Биология 7 класс. Учебник: Биология. Животные, В.В. Латюшин, В.А. Шапкин. Москва Дрофа (с 2005 по 2012 г). Учитель: Агарков Сергей Иванович Эл. почта: [email protected] Skype: s-agarkov1957 Время связи: пятница с 13.00 до 14.00 Пояснительная записка. Требования к уровню подготовки учащихся. В результате изучения биологии ученик должен знать/понимать: • особенности жизни как формы существования материи; • фундаментальные понятия биологии; • о существовании эволюционной теории; • основные группы...»

«Тема 14: Социальная ответственность и здоровье Юдин Борис Григорьевич, доктор философских наук, профессор, член-корр. РАН ВСЕОБЩАЯ ДЕКЛАРАЦИЯ О БИОЭТИКЕ И ПРАВАХ ЧЕЛОВЕКА (принята 19 октября 2005 г. на 33-й сессии Генеральной конференции ЮНЕСКО) Статья 14 - Социальная ответственность и здоровье (а) Содействие улучшению здоровья и социальному развитию своего населения является одной из основных целей правительств, которую разделяют все слои общества. (b) Ввиду того, что достижение наивысших...»

«Протокол № 5 заседания Экспертного совета при Правительстве Тверской области по предоставлению грантов социально ориентированным некоммерческим организациям в целях содействия реализации ими целевых социальных программ (социальных проектов) 13 cентября 2013 года г. Тверь Председательствующий – Раджабов Ян Рамазанович, заместитель руководителя аппарата Правительства Тверской области, заместитель председателя Экспертного совета. Присутствовали: Гагарин А.В., Гальчинская Е.А., Воякина О.Р.,...»






 
2014 www.av.disus.ru - «Бесплатная электронная библиотека - Авторефераты, Диссертации, Монографии, Программы»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.