ASM_R4 (663523)
Текст из файла
Раздел 4: Вызов функций С из языка ассемблера
4.1 Вызов С и С++ из ассемблера
До сих пор рассматривалось, как разделить переменные между С или C++ и ассемблером, а также как вызывать внешние ассемблерные функции из программ, написанных на С или C++. Теперь подойдем к этому с другой стороны, т.е. к вызову функций С или C++ из ассемблерного модуля - это также возможно, но требует большего внимания.
Если функция не обладает параметрами, процесс достаточно прост. Надо объявить функцию С или C++ в директиве EXTRN и воспользоваться инструкцией call:
CODESEG
EXTRN _cfuntion:proc
......
call _cfunction
Здесь предполагается, что функция, названная _cfunction, существует в программе, подлежащей компоновке вместе с ассемблерным модулем.
Если функции требуются параметры, процесс усложняется. Простые параметры, такие как символы и целые числа часто передаются непосредственно в стек. Сложные переменные, такие как строки, структуры и множества, передаются посредством ссылок, т.е. по адресу. Кроме того, многие функции возвращают результат в специфичные регистры. При вызове функций С или C++ из языка ассемблера надо самим позаботиться о подобных нюансах.
Сперва рассмотрим простейший случай вызова функции с одним целочисленным параметром:
void showscore( int thescore)
{
printf(“\nThe score is: %d\n, thescore);
}
Чтобы вызвать функцию showscore из ассемблерного модуля, передавая значение переменной типа слова в качестве thescore, можно написать:
CODESEG
EXTRN showscore: proc
mov ах, 76 ; Присвоение score регистру
push ах ; Передача параметра в стек
call _showscore ; Вызов функции С
pop ах ; Фиксация стека
Прежде всего, значение score присваивается ах (любой другой регистр точно так же подойдет для этого), а затем выталкивается в стек перед вызовом showscore. После возврата из функции слово выталкивается из стека. Это необходимо потому, что в С и C++ вызывающая программа удаляет параметры из стека. Если имеется несколько параметров, может быть, будет лучше просто прибавить их общее число байтов к sp. Например, чтобы вызвать функцию, которая оперирует четырьмя 16-битовыми параметрами, можно воспользоваться следующими командами:
push [vl] ; Выталкивание четырех переменных
push [v2] ; (не показанных) в стек
push [v3]
push [v4]
call _aCfunction ; Вызов функции С
add sp, 8 ; Удаление параметров
Выталкивание нескольких параметров осуществляется в порядке, обратном тому, в каком они объявляются функции С или C++. Исходя из предположения, что функция fillstring определена как
void fillstring( unsigned char far *thestring, int stringLength, char fillchar );
для вызова этой функции из языка ассемблера и заполнения строковой переменной пробелами требуются несколько шагов. Сперва ассемблерный модуль объявляется строковой переменной:
DATASEG
PUBLIC _astring
_astring db 80 dup (0)
Затем этот же модуль объявляет fillstring в директиве EXTRN и вызывает функцию для заполнения строчной переменной пробелами:
CODESEG
EXTRN _fillstring: ргос
xor ah, ah ; Обнуление ст. половины ах
mov al,’ ‘ ; Присвоение пробела а1
push ах ; Проталкивание пар-ра fillchar
mov ах, 79 ; Присвоение длины строки ах
push ах ;Проталкивание пар-ра дл. строки
push ds ;Проталкивание сег-та адреса строки
mov ах, offset _astring ;Присвоение смещения адреса ах
push ах ;Проталкивание смещ. адреса строки
call _fillstring ; Вызов функции
add sp, 8 ; Удаление параметров из стека
Каждый из параметров - заполняющий символ, длина строки и 32-битовый указатель строковой переменной- проталкивается в стек в порядке, обратном перечисленному в определении функции. Применительно к указателю - сегмент адреса проталкивается перед смещением. После обращения к _fillstring к указателю стека sp добавляются 8 байт, удаляя параметры из стека.
Несмотря на то что в этом примере функция _fillstring в действительности написана на языке ассемблера, вызовы функций С и C++ ничем не отличаются.
4.2 Локальные переменные
В дополнение к переменным, объявленным в сегменте данных либо общим с программой С и С++, можно использовать локальные переменные, помещенные в стек создаваемых ассемблерных модулей. Локальные переменные существуют только во время выполнения функции. Стековая часть создается для переменных при запуске функции, а затем очищается перед ее завершением. Таким образом, другие функции могут использовать эти же области памяти для своих собственных локальных переменных, снижая общий объем памяти, требуемой для всей программы. Например:
void countup()
{
int i;
for (i = 0; i < 10; i++)
printer("%d", i);
}
Целая переменная i помещается в памяти в стек при запуске функции countup и существует только до тех пор пока выполняется эта функция. В ассемблерном модуле можно проделать тоже самое с помощью директивы LOCAL. Вот пример законченной функции:
PROС _cfunction NEAR
LOCAL i:Word=stacksize
push bp
mov bp, sp
sub sp, stacksize
mov [i], 0
@@10:
inc [ i ]
;
;--Код, использующий локальную переменную [i]
;
cmp [i], 10
jne @@10
mov sp, bp
pop bp
ret ; Возврат в точку вызова
ENDP _cfunction
Директива LOCAL в этом примере подготавливает переменную i типа Word (слово). Указание = stacksize назначает общее число байтов, занимаемое всеми локальными переменными - в данном случае 2 байта. Это значение вычитается из sp после подготовки адресации переменных в стек. Затем, для ссылки на i, используются такие инструкции, как mov, inc и crop. Благодаря директиве LOCAL ссылки типа [i] переводятся следующим образом:
mov [bp-2], 0
inc [bp-2]
и т.д. При использовании LOCAL нет необходимости вычислять отрицательные смещения относительно bp, чтобы определить местоположение переменных в стеке, -достаточно воспользоваться именами переменных.
Поскольку bp не изменяется во время выполнения этой функции, можно восстановить sp по средством bp, удаляя область локальной переменной из стека, или прибавить stacksize к sp с помощью команды
add sp, stacksize
Подходят оба метода, но восстановление sp посредством bp - быстрее. Можно также объявить несколько локальных переменных операторами, подобными следующему:
LOCAL i:Word; j:Word; c:Byte=stacksize
Теперь, после вычитания stacksize из указателя стека для резервирования области в стеке, можно использовать три локальные переменные - i, j и с. (Необходимо всегда делать LOCAL, что упрощает адресацию локальных переменных, это не создает область для переменных в памяти.)
4.3 Передача аргументов
Совместное использование C++ и ассемблера становится более сложным, когда к функциям добавляются аргументы. Приходится очень внимательно программировать, обращаясь к функциям из различных модулей и выбирая аргументы из стека. Но следующая директива берет на себя задачу сама произвести ломку имен и занести их в стек:
ARG c_offset:byte, k_pffset:word
Аргументы, перечисленные таким образом, не являются объектами данных; они смещаются в стеке относительно регистра bр. Использование ARG подобным образом позволяет ассемблеру вычислить смещения вместо нас - но мы должны специфицировать правильные типы данных. Символьная переменная в C++ является байтом в ассемблере, целая в C++ - эквивалентом ассемблерного слова и т.д.
Обратный процесс - передача аргументов из языка ассемблера в C++ - требует иной тактики:
proc _asmfunction C c_arg:byte, k_arg:word
“C” после имени функции указывает, что аргументы приводятся для языка С (т.е. они выталкиваются в стек в порядке справа налево). Остальное также, как и для директивы ARG.
В результате Turbo Assembler автоматически пишет инструкции для сохранения, инициализации и восстановления bp. При использовании этой альтернативной методики не приходится проводить точные операции по выталкиванию bp. За исключением этого отличия, в остальном процесс программирования остается тем же самым.
19
Характеристики
Тип файла документ
Документы такого типа открываются такими программами, как Microsoft Office Word на компьютерах Windows, Apple Pages на компьютерах Mac, Open Office - бесплатная альтернатива на различных платформах, в том числе Linux. Наиболее простым и современным решением будут Google документы, так как открываются онлайн без скачивания прямо в браузере на любой платформе. Существуют российские качественные аналоги, например от Яндекса.
Будьте внимательны на мобильных устройствах, так как там используются упрощённый функционал даже в официальном приложении от Microsoft, поэтому для просмотра скачивайте PDF-версию. А если нужно редактировать файл, то используйте оригинальный файл.
Файлы такого типа обычно разбиты на страницы, а текст может быть форматированным (жирный, курсив, выбор шрифта, таблицы и т.п.), а также в него можно добавлять изображения. Формат идеально подходит для рефератов, докладов и РПЗ курсовых проектов, которые необходимо распечатать. Кстати перед печатью также сохраняйте файл в PDF, так как принтер может начудить со шрифтами.