Файл: 2005 Рудольф Марек. Ассемблер на примерах. Базовый курс. .pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 26.10.2023

Просмотров: 148

Скачиваний: 12

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
Глава 13. Компоновка — стыковка ассемблерных программ Макрос ргос определяет начало функции printit. Подстановка превращает его в две команды push ebp и mov ebp,esp. Следующий макрос arg определяет наш единственный аргумент. Если нужно передать несколько аргументов, то первый arg будет соответствовать крайнему слева аргументу в коде С. Размер аргумента по умолчанию — 4 байта (определен в с32.тас). ргос printit
%$what arg Оставшаяся часть программы понятна mov eax,[ebp + %$what] add eax,[plus] push eax push strl call printf endproc читаем первый аргумент из стека прибавляем глобальную переменную plus сохраняем в стеке последний аргумент функции printf первый аргумент - строка формата вывода вызываем p r i n t f макрос e n d p r o c восстанавливает ЕВР, уничтожает все локальные переменные у нас их нет) и выходит из подпрограммы Вся программа представлена в листинге 13.1. Листинг 13.1. Пример компоновки ассемблерного кода с С-кодом
%include «misc/c32.mac» section .text extern plus extern printf global printit proc printit
%$what arg mov eax,[ebp + %$what] add eax,[plus] push eax push strl call printf endproc section .data strl db «SUM = S>d»,0x0A
; подключаем макросы начало секции кода объявляем глоб. переменную p l u s объявляем глоб. функцию p r i n t f экспортируем функцию p r i n t i t начало функции p r i n t i t , принимающей один аргумент по имени what читаем из стека аргумент прибавляем глобальную переменную p l u s сохраняем в стеке последний аргумент функции p r i n t f первый аргумент — строка формата вывода вызываем p r i n t f макрос e n d p r o c восстанавливает ЕВР, уничтожает все локальные переменные у нас их нет) и выходит из подпрограммы секция данных
,0x0 ; строка формата, завершенная символом перевода строки и нулевым байтом
225
Ассемблер на примерах. Базовый курс Сохраним нашу программу в файле printit.asm и откомпилируем его nasm -f e l f p r i n t i t . a s m Исходный код С-программы сохраним в файле main.c и откомпилируем его с помощью gcc, скомпоновав с модулем printit.o: дсс -о printit main.c printit.o Запустив полученную программу printit, мы увидим, что она выводит
«SUM = И. Чтобы собрать 16-битную версию программы, нужно подключить другой заголовочный файл — с16.тас. Макросы ргос и endproc сами решают проблему си вызовами. При использовании модели памяти нужно указать
%define FARCODE Обо всем остальном позаботятся макросы. Если вы используете компилятор, требующий символов подчеркивания, вам поможет небольшой макрос
%macro c g l o b a l l g l o b a l _%1
%define %1 _%1
%endmacro
%macro c e x t e r n 1 e x t e r n _%1
%define %1 _%1
%endmacro После этого вы можете использовать директивы cglobal и cextern вместо обычных global и extern. Новые версии директив автоматически будут добавлять символы подчеркивания.
13.4. Компоновка с программой В общих чертах механизм передачи аргументов в Паскале не отличается от только что рассмотренного механизма в языке С. Аргументы передаются через стек, оба типа подпрограмм (процедуры и функции) используют стек-фрейм (или его 16- битную версию. Переменные и аргументы доступны через регистр ВР. Паскаль изначально разрабатывался как язык для обучения программированию, поэтому он не поддерживает некоторых конструкций языка С — например, функций с переменным количеством аргументов. Поэтому компилятор Паскаля помещает аргументы в стек слева направо, а не в обратном порядке, как в С. Вызов внешних подпрограмм на Паскале из ассемблерной программы упрощен, потому что в Паскале используются только вызовы. Генеральная уборка стека — забота не вызывающей программы, а вызываемой функции,
226

Глава 13. Компоновка — стыковка ассемблерных программ которая должна выполнить команду retf с аргументом, указывающим, сколько байтов выбросить из стека. Рассмотрим таблицу размещения стека подпрограммы относительно ВР (табл. 13.4). Таблица размещения стека подпрограммы относительно ВР Таблица 13.4 Адрес
[ В Р - . . . ]
[ВР + 0]
[ВР + 2]
[ВР + 4]
[ВР + 6]
[ВР+...] Назначение Локальные переменные Исходное значение ВР (2 байта) Адрес возврата — регистр IP (2 байта) Сегмент адреса возврата — регистр CS (2 байта) Первый аргумент Следующие аргументы Давайте напишем на Паскале программу, подобную только что рассмотренной. Новая версия нашей программы для вывода значения суммы будет вызывать функцию writeln из основной программы, то есть подпрограмма addit должна только подсчитать сумму и вернуть ее в основную программу.
{$L a d d i t . o b j } uses c r t ; var p l u s : i n t e g e r ; function a d d i t ( x : i n t e g e r ) : l o n g i n t ; f a r ; e x t e r n a l ; begin p l u s := 6; writelnCSUM = ', a d d i t ( 5 ) ) ; end. Функцию addit, как ив предыдущем примере, напишем на языке ассемблера. Программе на Паскале она становится известна посредством ключевого слова
external. В той же строке декларации мы объявляем, что функции addit нужно передать один целочисленный параметр, она возвращает значение типа longint
(4 байта) и вызывается как FAR. He забудьте также написать директиву $L, указывающую имя объектного файла с откомпилированной функцией addit, который нужно подключить при компоновке. Теперь напишем функцию addit, которую мы сохраним в файле addit.asm.
Borland Turbo Pascal использует нестандартный формат объектного файла obj, а свой собственный, что накладывает строгие ограничения наименование секций программы. Секция кода должна называться CODE, CSEG или именем, заканчивающимся на «_ТЕХТ», секция данных — CONST или именем, заканчивающимся на «_DATA», а секция неинициализированных данных —
DATA, или DSEG, или именем, заканчивающимся на «_BSS». Если вы уже привыкли называть секции программы именами .text, .data и .bss, тов программах, предназначенных для компоновки с Паскаль-кодом, просто добавьте знак подчеркивания после точки, и компилятор будет доволен.
227
Ассемблер на примерах. Базовый курс Функция addit будет вызываться в 16-битной среде, где размер типа данных integer равен 2 байтам. Возвращает функция значение типа longint (4 байта) и передает его через пару регистров DX:AX. Все эти вопросы, в том числе вопросы компоновки с Паскаль-кодом, решает макрос с16.тас. Код нашей подпрограммы addit представлен в листинге 13.2. Листинг 13.2. Пример подпрограммы для паскалевской программ
SECTION ._TEXT
%define PASCAL
%include «misc/cl6.mac» extern plus global addit proc addit
%$what arg xor dx,dx mov ax,[bp+%$what] add ax,[plus] adc dx,0 endproc начало секции кода будем использовать вызовы подключаем макросы получаем доступ к внешней переменной plus экспортируем функцию addit начало функции addit макрос включает создание стек-фрейма объявляем единственный аргумент по имени what сбрасываем DX АХАХ АХ + plus не забудьте флаг переноса удаляем полученные аргументы и выходим из подпрограммы Макрос arg принимает в качестве необязательного параметра размер передаваемого аргумента. Размер по умолчанию в 16-битной среде равен 2 байтам. Если бы мы передавали аргумент типа longint или указатель, нам пришлось бы явно задать его размер, то есть 4 байта. Теперь посмотрим, во что превратятся макросы после подстановки
CS
CS
CS
CS
C S
CS
CS
CS
CS
0076 0077 0079 В ЕЕ ВЕС
СА0200 push mov xor mov add adc mov pop retf bp bp,sp dx,dx ax,[bp+0 6] ax,[0052] dx,0000 sP/bp bp
0002 макрос proc макрос proc
;DX=0 получаем й аргумент сложение аргумента и переменной plus сложение с переносом макрос endproc макрос endproc макрос endproc все После компиляции и запуска программы она выведет требуемую сумму на экран.
228

Заключение Несмотря на то, что вы дочитали эту книгу до конца, ваше изучение языка ассемблера на этом не заканчивается, а, наоборот, только начинается. Вы заложили только фундамент дальнейшего изучения, познакомившись с основными понятиями и конструкциями языка ассемблера, которых должно хватить для написания простеньких программ. Если вы заинтересовались и хотите разрабатывать сложные ассемблерные программы, рекомендуем ознакомиться с расширенными наборами команд процессоров (ММХ, SSE, 3DNow), описания которых вы найдете в Интернете. А также прочитать книгу, посвященную программированию на языке ассемблера под конкретную операционную систему — DOS, Windows или Linux. Все программы и фрагменты программ, представленные в этой книге, распространяются свободно без лицензионных ограничений. Все торговые марки и наименования программных продуктов являются зарегистрированными торговыми марками их владельцев. Ассемблер на примерах. Базовый курс
Глава 15 Часто используемые команды Ассемблер на примерах. Базовый курс

15. Часто используемые команды Группа команд Команды перемещения значений Арифметические команды Логические команды Сравнение Сдвиги ротация Команды перехода Условные переходы Подпрограммы Операции над строками Назначение
MOV — скопировать
XCHG — поменять местами значения
PUSH — сохранить в стеке
POP — извлечь из стека
ADD — сложение
SUB — вычитание
MUL — умножение
DIV деление
INC — инкремент (увеличение на 1)
DEC — декремент (уменьшение на 1)
AND — логическое И (логическое умножение)
OR — логическое ИЛИ (логическая сумма)
XOR — исключительное ИЛИ
NOT отрицание
СМР сравнение
TEST — поразрядное сравнение
SHR — логический (поразрядный) сдвиг вправо
SHL — логический (поразрядный) сдвиг влево
RCR — ротация через флаг переноса вправо
RCL — ротация через флаг переноса влево
JMP — безусловный переход
LOOP — переход, пока (Е)СХ не сравняется с 0
JZ — если флаг нуля (ZF) установлен
JC — если флаг переноса (CF) установлен
JNZ — если флаг нуля (ZF) не установлен
JNC — если флаг переноса (CF) не установлен
CALL — вызов подпрограммы
RET — возврат из подпрограммы
INT — вызов прерывания
REP — повторять следующую команду, пока (Е)СХ не 0
MOVSx — копирование строк
CMPSx — сравнение строк
SCASx — поиск в строке
231