Ответы на билеты / Билет_17_
.docИнтерфейс программ на языке ассемблера с программами на языке Си.
Вызов ассемблера из Си.
Наиболее простым способом объединения частей программы, написанных на Си и ассемблере, является использование в тексте встроенного (in - line) ассемблера.
Любая строка Си - программы начинающаяся с ключевого слова asm, до символа ';' или символа перевода строки рассматривается как инструкция на ассемблере.
Для встроенного ассеблера разрешается использовать:
1. исполняемые инструкции (машинные комманды);
2. цепочные примитивы ( инструкции манипуляции подряд расположенными байтами или словами ) с префиксом повторения ибез него;
3. все инструкции передач управления (JUMP, CALL, LOOP, RET, IRET) с прямой или косвенной адресацией;
4. директивы описания распределения данных (db, dw, dd, extrn).
Для встроенного ассемблера нельзя использовать его директивы, управляющие его работой: ASSUME, SEGMENT, ENDS, PROC, ENDP, ORG и т.д.
При задании операндов в ассемблерных инструкциях разрешается ссылаться на уже описанные переменные Си функции, поля структурных переменных и объединений, метки, имена функций и т.п.
В ассемблерных инструкциях нельзя использовать имя группы DGROUP, имена сегментов _TEXT, _STACK, _DATA и т.п.
Рассмотрим пример простейшей программы, выполняющей суммирование двух целых чисел. Ввод и вывод производятся в Си, а сложение - в ассемблере.
#pragma inline /* эта деректива указывает компилятору на то, что
в программе есть ассемблерные строки*/
void main()
{
int i,j,s;
puts("Введите значения i и j");
scanf("%d%d",&i,&j); /* ввод значений i и j */
asm push ax /* значение регистров ax и bx */
asm push bx /* помещается в стек */
asm mov ax,i /* в ах заносится введенное значение i */
asm mov bx,j /* в bx заносится введенное значение j */
asm add ax,bx /* сумма ax и bx сохраняется в ax */
asm mov s,ax /* содержимое ax передается в s */
asm pop bx /* из стека востанвливаются */
asm pop ax /* значения регистров ax и bx */
printf("i + j = %d\n",s); /* вывод результата */
}
Эту же программу можно записать по другому:
#pragma inline
void main()
{
int i,j,s;
puts("Введите значения i и j");
scanf("%d%d",&i,&j);
asm
{
push ax bx
mov ax,i
mov bx,j
add ax,bx
mov s,ax
pop bx ax
}
printf("i+j=%d\n",s);
}
Если имеются переменные, описанные в пределах ассемблерного модуля на который выполняется ссылка в Си-функции, то они объявляются как PUBLIC:
PUBLIC имя_переменной
Имя ассемблерной процедуры, вызываемой из Си, в ассемблерном блоке должно описываться как PUBLIC, что делает это имя видимым при редоктировании связей.
Turbo C накладывает определенные ограничения на запись имен переменных и функций, вытекающие из особенностей работы компилятора и компоновщика.
1. При объявлении внешнего идентификатора, в том числе и имен функций, которые по умолчанию являются внешними, компилятор Си автоматически добавляет символ подчеркивания "_" перед именем и в таком виде сохраняет его в объектном модуле.
В то же время ассемблеры TASM и MASM не добавляют символ подчеркивания.
2. Компилятор TURBO C для всех внешних идентификаторов сохраняет регистр букв, т.е. является "регистрочувствительным" (case sensetive), и такое поведение Си компилятора не возможно изменить. В тоже время TASM и MASM при записи внешних идентификаторов в объектном модуле приводят их к верхнему регистру, т.е. все малые буквы преобразовываются в большие. Такое поведение по умолчанию можно переопределить, используя опцию /mx. Ассемблирование таким образом сохраняет