
- •1. Внутренние регистры
- •1.1. Регистры данных
- •1.2. Регистры сегментов
- •1.3. Регистры указателей и индексов
- •1.4. Регистр командного указателя
- •1.5. Флаговый регистр
- •2. Структура и процесс разработки программы на языке ассемблера
- •2.1. Команды
- •2.2. Псевдооператоры
- •2.2.1. Псевдооператор segment
- •2.2.2. Псевдооператор proc
- •2.2.3. Псевдооператор assume
- •2.2.4. Псевдооператор end
- •2.2.5. Псевдооператоры определения данных
- •2.3. Инициализация программы
- •3. Команды пересылки данных
- •3.1. Команда mov
- •3.2. Команды push и рор
- •4. Режимы адресации
- •4.1. Регистровая и непосредственная адресация
- •4.2. Исполнительный адрес
- •4.3. Прямая адресация
- •4.4. Косвенная регистровая адресация
- •4.5. Адресация по базе
- •4.6. Прямая адресация с индексированием
- •4.7. Адресация по базе с индексированием
- •5. Команды передачи управления
- •5.1. Команды call и ret
- •5.2. Команда безусловного перехода jmp
- •5.3. Команды условной передачи управления
- •5.4. Команды управления циклами
- •6. Команды обработки строк
- •6.1. Команды пересылки строк movs, movsb, movsw
- •6.2. Префиксы повторения
- •6.3. Команды сравнения строк. Команда cmps.
- •6.4. Команды сканирования строк
- •6.5. Команды загрузки и сохранения строки
- •7. Взаимодействие языков Си и Ассемблера
- •7.1. Внутренняя структура программы на языке Си для ibm pc
- •7.2. Использование функций на языке Ассемблера
- •7.2.1. Основы взаимодействия языков Си и Ассемблера
- •7.2.2. Передача управления в подпрограмму и обратно
- •7.2.3. Использование глобальных данных
- •7.2.4. Использование аргументов функции
- •7.2.5. Возвращение значения через имя подпрограммы
- •7.2.6. Использование аргументов
- •7.3. Вызов функций на языке Си из программ на языке Ассемблера
- •7.4. Использование локальных данных
- •8. Арифметические команды
- •8.1. Форматы хранения десятичных чисел
- •8.2. Команды сложения
- •8.3. Коррекция результата сложения для bcd-форматов
- •8.4. Команда приращения значения приемника на единицу
- •8.5. Команды вычитания
- •8.6. Коррекция результата вычитания для bcd-форматов
- •8.7. Команда уменьшения содержимого приемника на единицу
- •8.8. Команда обращения знака
- •8.9. Команды умножения
- •8.10. Коррекция результатов умножения
- •8.11. Команды деления
- •8.12. Коррекция результатов деления
- •8.13. Команды расширения знака
- •9. Команды манипулирования битами
- •9.1. Логические команды and, or и xor
- •9.2. Команда логического отрицания nот
- •9.3. Команда проверки test
- •9.4. Команды сдвига и циклического сдвига
- •9.4.1. Команды сдвига
- •9.4.2. Команды циклического сдвига
- •10. Команды работы с флагами
- •10.1. Команды управления флагами
- •10.2. Команды пересылки флагов
- •11. Псевдооператоры определения идентификаторов и операции
- •11.1. Псевдооператоры определения идентификаторов
- •11.2. Операции
- •11.2.1. Арифметические операции
- •11.2.2. Логические операции
- •11.2.3. Операции отношения
- •11.2.4. Операции, возвращающие значения
- •11.2.5. Операции присваивания атрибутов
- •12. Условные псевдооператоры
- •13. Макроопределения
- •13.1. Сравнение макроопределений и процедур
- •13.2. Состав макроопределений
- •13.3. Псевдооператоры макроассемблера
- •13.3.1. Псевдооператор local
- •13.3.2. Псевдооператоры повторения
- •13.3.3. Условные псевдооператоры
- •13.3.4. Псевдооператор eхiтм
- •13.4. Операции в макроопределениях
- •13.5. Задание макроопределений в исходных программах
- •13.5.1. Использование библиотеки макроопределений
- •13.5.2. Указания для задания макроопределений
- •13.5.3. Считывание библиотеки макроопределений в программу
- •13.5.4. Удаление макроопределений
7.2. Использование функций на языке Ассемблера
в программах на языке Си
Основной целью создателей языка Си была разработка такого языка программирования высокого уровня, который можно было бы использовать вместо языка Ассемблера для системного программирования. Язык Си вполне соответствует своему предназначению.
Однако в отдельных случаях программисту может понадобиться и язык ассемблера. В конкретной программе такие случаи обычно составляют небольшую часть ее кода.
Если это имеет место, то программист старается пользоваться языком Си для написания основных модулей приложения, а небольшие, но критичные фрагменты программы выполняет в виде функций на языке ассемблера, которые вызываются из программы на языке Си.
Заметим, что различные компиляторы языка Си организуют указанное взаимодействие не совсем одинаково. При работе с конкретным компилятором необходимо выяснять и учитывать имеющиеся особенности.
Будем считать, что в дальнейшем используется модель распределения памяти с малыми кодами (до 64 Кбайт). Изменения, которые надо внести в программы, если вызывающая функция написана для модели больших кодов, обговорим в конце.
Процесс создания программы:
– откомпилировать модуль на языке Си с помощью компилятора языка Си,
– откомпилировать ассемблерный модуль,
– с помощью программы компоновщика создать на основе двух объектных файлов один выполняемый файл *.ЕХЕ.
7.2.1. Основы взаимодействия языков Си и Ассемблера
Первое требование, которое необходимо выполнить при совместной компоновке нескольких объектных файлов, созданных ассемблером и компилятором языка Си, состоит в том, что все объектные файлы должны иметь одинаковый формат – тот, который нужен загрузчику. Проблемы могут возникнуть при работе с объектными файлами, получаемыми с помощью средств разных производителей.
Другое требование – функция на языке ассемблера должна учитывать соглашения по вызову функций, используемые компилятором языка Си. Для этого программист должен усвоить ряд деталей, которые можно почерпнуть либо из документации компилятора, либо анализируя машинный код, выдаваемый компилятором.
Изучая соглашения по вызову функций, будем называть вызывающую функцию на языке Си программой, вызываемую функцию на языке ассемблера – подпрограммой.
Необходимо учитывать следующие соглашения:
– подпрограмма не должна уничтожать регистровые значения программы (называемые средой);
– программа и подпрограмма должны придерживаться общих соглашений о передаче данных из программы в подпрограмму и о возвращении данных из подпрограммы в программу.
7.2.2. Передача управления в подпрограмму и обратно
При вызове программой на языке Си подпрограммы на языке ассемблера должны быть выполнены следующие шаги.
1. Программа должна сохранить адрес команды, с которой будет продолжено ее исполнение после завершения вызова подпрограммы. Затем программа передает управление подпрограмме.
2. После завершения подпрограмма должна возвратить управление по адресу, сохраненному ранее программой.
Реализация описанных шагов требует, чтобы программа сохранила адрес возврата в таком месте, которое доступно подпрограмме.
Для этого используется стек. Каждая функция должна поместить адрес возврата в стек, а затем передать управление подпрограмме. Когда подпрограмма завершает работу, она извлекает из стека последний адрес возврата и возвращает управление этой ячейке памяти. Т.е. механизм, используемый ассемблером, используется и в языке Си.
Рассмотрим пример. Получая оператор языка Си вида
f1( );
компилятор языка Си генерирует машинную команду
CALL _f1
Символическое имя _f1 соответствует глобальному идентификатору, определенному в подпрограмме.
Приведем пример подпрограммы на языке ассемблера:
PGROUP GROUP PROG ; не обязателен
PROG SEGMENT BYTE PUBLIC 'PROG'
ASSUME CS: PGROUP
PUBLIC _F1 ; Сделать это имя глобальным
_F1 PROC NEAR ; Малая модель
RET ; Вернуться в вызывающую программу
_F1 ENDP ; Конец программы
PROG ENDS ; Конец сегмента
END ; Конец файла
Псевдооператор GROUP служит для указания ассемблеру на то, что этот сегмент команд надо поместить вместе с командами других модулей в один блок памяти размером 64 Кбайт.
Псевдооператор PUBUC предлагает ассемблеру сделать идентификатор F1 глобальным, чтобы он стал доступен компоновщику. Это позволяет компоновщику выполнять требуемую связь с вызывающей функцией на языке Си.
Рассмотрим способы обмена данными между функцией на языке Си и подпрограммой на языке ассемблера.
Существует два способа обмена данными между вызывающей функцией и подпрограммой на языке ассемблера: использование глобальных данных и аргументов. Рассмотрим каждый из них отдельно.