Информатика на пять О нас
 Добавить в избранное
5byte.ru
 Теория
 8 класс
 9 класс
 10 класс
 11 класс
Задания
 8 класс
 9 класс
 10 класс
 11 класс
Книги
Тесты
ЕГЭ
Turbo Pascal 7
 Описание
 Задачи
HTML
Рефераты

12. Использование языка ассемблера в программах на Turbo Pascal 7

Данный раздел не является справочным по языку ассемблера и предполагает знание читателем основ этого языка и устройство процессора 80X86.

Turbo Pascal позволяет писать отдельные части программы (подпрограммы или части подпрограмм) на языке ассемблера. Здесь возможны четыре варианта.

Во-первых, можно написать подпрограмму на языке ассемблера, скомпилировать ее отдельно компилятором TASM (Turbo Assembler) с получением объектного файла, а затем скомпоновать его с основной программой, написанной на Turbo Pascal, используя при этом директиву компилятора {$L <имя файла>}, где <имя файла> - имя файла с подпрограммой на ассемблере, и директиву external.

Во-вторых, используя встроенный ассемблер пакета Turbo Pascal, отдельные части текста программы можно написать непосредственно на языке ассемблера, заключив их в операторные скобки asm...end.

В-третьих, ту или иную подпрограмму (процедуру или функцию) можно полностью, за исключением заголовка, написать на языке ассемблера, используя при этом директиву assembler. В этом случае также используется встроенный ассемблер.

Наконец, в-четвертых, можно небольшую подпрограмму написать непосредственно в кодах процессора, используя оператор или директиву inline.

При написании отдельных частей программы на языке ассемблера следует иметь в виду, что необходимо сохранить содержимое регистров ВР, SP, SS и DS. Если их необходимо изменить, то исходные значения следует запомнить, а затем восстановить. Остальные регистры можно безболезненно изменять.

Основным вопросом стыковки программы с подпрограммой, написанной на ассемблере, является передача параметров в подпрограмму и обратно. Именно этому вопросу и будет здесь уделено основное внимание.

Ниже будут рассмотрены особенности использования этих вариантов. В качестве примера их использования будут приведены различные варианты подпрограммы-функции, определяющей максимальный элемент из массива целых чисел.

12.1. Использование компилятора TASM

Как правило, этот вариант применяется, когда та или иная программа имеет большой размер и ее целесообразно и написать, и скомпилировать отдельно, используя компилятор TASM [5]. В этом случае можно использовать все возможности языка и компилятора TASM.

Пример. Программа, использующая подпрограмму-функцию, определяющую максимальный элемент из массива целых чисел и написанную на языке ассемблера.

Основная программа, использующая подпрограмму, написанную на языке ассемблера, содержит инициализированный массив, в котором будет определяться максимальное число, а сама программа выводит на экран значение максимального числа из этого массива:

program EXAMPLE20;  
const  
  N = 7 {Размер массива}
  Massiv: array[1..n] of Integer = (1, 2, 3, 2, 17, 7, 2); {Исходный массив}
{$L SUBR} {Подключение файла SUBR.OBJ}
function Max(var Mas; N: Integer): Integer; external;  
begin  
  WriteLn('Максимальное число массива равно: ' , Max(Massiv, N));  
  ReadLn  
end.  

Используя стандартную модель памяти, подпрограмму, определяющую максимальное число из массива, можно написать следующим образом:

CODE SEGMENT BYTE PUBLIC
  ASSUME CS:CODE    
  PUBLIC Max   ;внешний идентификатор
AdrMas EQU DWORD PTR[BP+6] ;адрес первого параметра
N EQU WORD PTR[BP+4] ;второй параметр
Max   PROC NEAR  
  PUSH BP   ;сохранение регистра ВР
  MOV BP,SP   ;указатель стека
  LDS SI,AdrMas   ;адрес массива
  XOR AX, AX   ;0 - в регистр АХ
  MOV BX,8001h   ;минимальное целое число
  MOV CX,N   ;число элементов массива
  CMP CX,AX   ;сравнение с 0
  JLE M3   ;0 или отрицательное число
M1: LODSW     ;загрузка элемента массива
  CMP AX, BX   ;сравнение с текущим максимумом
  JLE M2   ;не больше
  MOV BX,AX   ;новое максимальное число
M2: LOOP M1   ;цикл
M3: MOV AX,BX   ;результат функции
  POP BP   ;восстановление регистра
BP        
  RET 6   ;возврат из подпрограммы
Max   ENDP    
CODE ENDS      
  END      

По приведенной подпрограмме следует сделать следующие замечания. Первые две команды - сохранение регистра ВР и загрузка в него указателя стека - являются типичными командами, с помощью которых можно установить доступ к передаваемым параметрам через регистр ВР.

Параметры передаются в подпрограмму следующим образом. Параметры-значения размером в один байт передаются одним 16-разрядным словом, причем информативным является младший байт, параметры-значения в 2 байта передаются одним 16-разрядным словом, в 4 байта - двумя 16-разрядными словами, параметры-значения типа Real передаются тремя 16-разрядными словами, все остальные параметры-значения (в том числе и 3-байтовые) передаются своими полными адресами. Из этого правила есть некоторые исключения: параметры-переменные и параметры-константы всегда передаются своими полными адресами.

Т. к. в подпрограмме первый параметр является параметром-переменной, то он передается своим адресом, с помощью которого в дальнейшем и извлекаются элементы массива. Второй параметр подпрограммы - параметр-значение, и он передается своим значением. Первый параметр находится по адресу ВР+6, а второй - ВР+4. Указанные смещения определяются наличием в стеке адреса возврата (при ближней адресации - 2 байта), размещенным в стеке значением регистра ВР (2 байта) и для первого параметра - размером второго параметра (2 байта).

Если подпрограмма является подпрограммой-функцией, то возвращаемый параметр передается различным образом в зависимости от своего размера. Параметр размером в байт передается в регистре AL, параметр размером в 2 байта - в регистре АХ, параметр размером в 4 байта - в регистрах DX (старшая часть или адрес сегмента) и АХ (младшая часть или смещение), параметры размером в 6 байтов (типа Real) - в регистрах DX (старшая часть), ВХ (средняя часть) и АХ (младшая часть). Параметры других вещественных типов передаются в нулевом элементе стека сопроцессора ST(0). Если функция возвращает значение типа string, то при обращении к функции резервируется память для размещения возвращаемой строки, а адрес этой области размещается в стеке выше всех передаваемых параметров.

В рассматриваемом примере возвращаемый параметр - типа Integer, и он возвращается в регистре АХ.

При возвращении из подпрограммы в команде RET записан аргумент 6 для удаления из стека передаваемых параметров, которые в данном примере имеют именно этот размер.

Turbo Assembler предполагает и другое оформление подпрограмм, используемых затем в программах, написанных на языке Паскаль. Для этого используется специальная модель памяти Large (большая), задаваемая в виде:

.MODEL Large,PASCAL.

Она позволяет несколько упростить оформление входа в подпрограмму и выхода из нее. Подпрограмма дополняется необходимыми командами на этапе компиляции.

Пример. Вариант предыдущей подпрограммы, использующий специальную модель памяти.

  .MODEL Large,PASCAL ; специальная модель памяти
  .CODE      
  PUBLIC Max   ;внешний идентификатор
Max   PROC NEAR Mas: DWORD, N: WORD
        ;передаваемые параметры
  LDS SI,Mas   ;адрес массива
  XOR AX, AX   ;0 - в регистр АХ
  MOV BX,8001h   ;минимальное целое число
  MOV CX,N   ;число элементов массива
  CMP CX,AX   ;сравнение с 0
  JLE @@3   ;0 или отрицательное число
@@1: LODSW     ;загрузка элемента массива
  CMP AX,BX   ;сравнение с текущим максимумом
  JLE @@2   ;не больше
  MOV BX,AX   ;новое максимальное число
@@2: LOOP @@1   ; цикл
@@3: MOV AX,BX   ;результат функции
  RET     ;возврат из подпрограммы
Max   ENDP    
  END      

В этом примере не сохраняется и не восстанавливается регистр ВР - эти операции добавляются к программе на этапе компиляции. Не указывается также и размер передаваемых параметров - они при выходе из подпрограммы удаляются автоматически. В строке, где начинается описание подпрограммы (начинается с имени подпрограммы - Мах), необходимо перечислить все передаваемые параметры в том же порядке, как они заданы в заголовке, написанном на языке Паскаль с указанием их размеров (о размерах передаваемых параметров см. выше).

Здесь показана также возможность использования в подпрограммах локальных меток, начинающихся символами @@.

В подпрограмме, написанной на языке ассемблера, можно использовать подпрограммы, написанные на языке Паскаль. Несколько модифицированная подпрограмма определения максимального элемента массива, которая в случае недопустимого числа элементов массива (0 или отрицательное число) вызывает подпрограмму, написанную на языке Паскаль для выдачи сообщения, приведена в следующем примере.

Пример. Модифицированный вариант программы, в котором подпрограмма, написанная на языке ассемблера, в случае недопустимого числа элементов массива (равно 0 или отрицательное) вызывает подпрограмму, написанную на языке Паскаль, выводящую соответствующее сообщение.

Основная программа, содержащая подпрограмму на языке Паскаль, будет иметь следующий вид:

program EXAMPLE21;
const
  N = 7                                    {Размер массива}
  Massiv: array[1..n] of Integer = (1, 2, 3, 2, 17, 7, 2);     {Исходный масcив}
{$l SUBR}                                  {Подключение файла SUBR, OBJ}
Function Max(var Mas; N :Integer) Integer; external;
procedure ErrorReport(N: Integer);
begin
  WriteLn;
  WriteLn('Недопустимое число элементов: ' , N);   ReadLn
end;
begin
  WriteLn('Максимальное число массива равно: ', Max(Massiv, N));
  ReadLn
end.

Подпрограмма, написанная на языке ассемблера, будет в этом случае иметь следующий вид:

  .MODEL Large,PASCAL ; специальная модель памяти
  .CODE      
  EXTRN ErrorReport: NEAR ;внешняя подпрограмма
  PUBLIC Max   ;внешний идентификатор
Max   PROC NEAR Mas: DWORD, N: WORD
        ;передаваемые параметры
  LDS SI,Mas   ;адрес массива
  XOR AX, AX   ;0 - в регистр АХ
  MOV BX,8001h   ;минимальное целое число
  MOV CX,N   ;число элементов массива
  CMP CX,AX   ;сравнение с 0
  JG @@1   ; допустимое число
  PUSH BX   ;сохранение регистра ВХ
  PUSH CX   ; передаваемый параметр
  CALL ErrorReport   ;обращение к подпрограмме
  POP BX   ;восстановление регистра ВХ
  JMP @@3   ;на завершение
@@1: LODSW     ;загрузка элемента массива
  CMP AX,BX   ;сравнение с текущим максимумом
  JLE @@2   ;не больше
  MOV BX,AX   ;новое максимальное число
@@2: LOOP @@1   ; цикл
@@3: MOV AX,BX   ;результат функции
  RET     ;возврат из подпрограммы
Max   ENDP    
  END      

Перед обращением к подпрограмме, написанной на языке Паскаль, в стек в соответствующем порядке следует поместить передаваемые параметры. В данном случае такой параметр один - число элементов массива.

Т. к. подпрограмма, написанная на языке Паскаль, не гарантирует сохранение регистров АХ, ВХ, СХ и DX, то в случае необходимости сохранения их значений следует перед обращением к подпрограмме, написанной на языке Паскаль, сохранить в стеке значения соответствующих регистров, а после возвращения из подпрограммы - восстановить их. В данном примере сохраняется содержимое регистра ВХ, в котором записано минимальное целое число.

При написании программ, содержащих отдельные части, написанные на языках ассемблера и Паскаль, следует обращать внимание на способ адресации (дальний - far или ближний - near). Здесь существует следующее правило: если подпрограмма объявляется в интерфейсной части какого-либо модуля, то она должна иметь дальнюю адресацию, в других случаях (подпрограмма объявляется в файле, содержащем основную программу, или в исполнительной части модуля) следует использовать ближнюю адресацию.

И еще одно замечание: внешнюю подпрограмму нельзя объявлять внутри другой подпрограммы.





свадьба в шатре
 У Вас есть материал пишите нам
 
    Copyright © 2008    
  Top.Mail.Ru