- •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.5. Возвращение значения через имя подпрограммы
Если подпрограмма возвращает только одно значение, то проще всего трактовать его как значение имени подпрограммы. Чтобы вызывающая программа могла воспринять возвращаемую сумму как значение имени подпрограммы, нужно следующим образом модифицировать наш пример
extern “C” void sum();
main ()
{
int val;
int x = 10;
val = sum(x, 20, 20+5);
printf( "val = %d\n", val );
}
Вызывающая функция и подпрограмма должны придерживаться определенных соглашений относительно возвращения значения через имя подпрограммы. Многие компиляторы языка Си рассчитаны на то, что это значение хранится в одном или нескольких регистрах.
Рассмотрим общепринятые соглашения по использованию этих ресурсов на IBM PC .
Тип возвращаемого значения |
Используемые регистры |
Целый (16 битов) |
АХ |
Длинный целый (32 бита) |
АХ, ВХ или DX, AX |
Вещественный с двойной точностью (64 бита) |
АХ, ВХ, СХ, DX |
Чтобы в соответствии с этими соглашениями модифицировать подпрограмму SUM, надо просто удалить ссылки на внешний объект VAL и оставить вычисленный ею результат в регистре АХ. Т.е. удалить строку
MOV VAL, AX ; Поместить результат в VAL
Программа на языке Си извлечет результат из регистра АХ, когда ей будет возвращено управление.
7.2.6. Использование аргументов
Если подпрограмма должна возвращать несколько значений, то она может использовать для этой цели свои аргументы. На языке Си это производится путем передачи аргументов по адресу. Доступ к аргументам, передаваемым по адресу, можно получить и в подпрограммах на языке ассемблера.
Еще раз модифицируем подпрограмму SUM: теперь у нее будет четыре аргумента и результат будет возвращаться через последний из них. Ее вызов будет иметь следующий вид:
sum(x, 20, 20+5, & val);
После загрузки адреса val в регистр ВХ мы сможем поместить по этому адресу значение, используя косвенную регистровую адресацию.
MOV ВХ, [ ВР ] +10 ; Загрузить адрес, по которому должен быть
; помещен результат
MOV [ ВХ ], АХ ; Поместить значение суммы по этому адресу
7.3. Вызов функций на языке Си из программ на языке Ассемблера
Чаще всего приходится вызывать подпрограммы на языке ассемблера из функций на языке Си. Однако можно вызывать функции на языке Си из программ на языке ассемблера.
Для этого надо объявить имя функции на языке Си в программе на языке ассемблера путем использования псевдооператора EXTRN, который должен следовать за псевдооператором SEGMENT.
Если имя функции на языке Си myfunc, то для моделей распределения памяти с малыми кодами ее объявление будет иметь вид
EXTRN _MYFUNC : NEAR
Чтобы вызвать функцию на языке Си, ее каждый аргумент нужно поместить в стек, начиная с последнего аргумента, а затем вызвать функцию с помощью команды CALL.
После возвращения из функции на языке Си программа на языке ассемблера должна очистить стек, удалив из него все ранее помещенные аргументы. Для этого можно с помощью команды POP извлечь их один за другим. Но легче всего просто увеличить содержимое указателя стека на целое значение, которое равно числу байтов, ранее помещенных в стек (напомним, что команда PUSH уменьшает содержимое указателя стека).
Приведем пример вызова из программы на языке Ассемблера функции на языке Си, которой требуются три целых аргумента.
PGROUP GROUP PROG
PROG SEGMENT BYTE PUBLIC 'PROG'
EXTRN _MYFUNC: NEAR ; имя Си-функции
ASSUME CS: PGROUP
PUBLIC ASMFUNC
ASMFUNC PROC NEAR
PUSH AX ; значения аргументов
PUSH ВХ ; находятся в регистрах
PUSH СХ ; АХ, ВХ и СХ
CALL MYFUNCT ; вызвать Си-функцию
ADD SP, 6 ; очистить стек от
................... ; значений аргументов
В этом примере перед исполнением команды CALL исполняются три команды PUSH, в результате чего содержимое указателя стека уменьшается на шесть байтов. Увеличение указатель стека SP на шесть после исполнения команды CALL позволяет восстановить его исходное содержимое.
Если данные определены внутри программы на языке ассемблера, то их можно сделать доступными функциям на языке Си, объявив их
– общедоступными с помощью псевдооператора PUBLIC в сегменте данных программы на языке ассемблера,
– внешними с помощью служебного слова extern в функции на языке Си.
