При рассмотрении передачи и возврата управления и данных необходимо учитывать следующие моменты:
· тип команд вызова и возврата;
· способы передачи параметров – по ссылке, по значению, для передачи по ссылке – тип адресации, передача сложных типов данных – массивов и структур;
· доступ к данным в подпрограмме;
· при передаче параметров через стек, в каком порядке помещать параметры в стек и какая из программ ответственна за очистку стека;
· как располагаются многомерные массивы в памяти;
· выполняется ли выравнивание полей структур на границу слова, двойного слова и т.п.;
· СП могут осуществлять обязательное преобразование данных некоторых типов при использовании их в качестве фактических параметров;
· как представляются сложные типы данных: структуры, записи и объекты (C++), записи, записи с вариантами, множества (Pascal).
Сохранение регистров
В СП для языков Pascal и C фирм MicroSoft и Borland для компьютеров типа IBM PC подпрограммы обязаны сохранять содержимое регистров CS, DS, SS, SP, BP. В других СП требования могут отличаться.
2.4. Соглашение о связях языка Pascal (сводка)
Преобразование имен
Значащая длина идентификатора может быть от 8 до 250 символов, умолчание – 32. Для изменения служит команда Options+Compiler+Source.
Строчные буквы преобразуются в прописные.
Передача и возврат управления
Тип подпрограмм (near или far) и, следовательно, команд call и ret зависит от двух факторов:
· обращение к внешним подпрограммам всегда осуществляется как к far подпрограммам;
· если включен режим Force Far Calls (команда Options+Compiler), то и подпрограммы внутри единицы трансляции рассматриваются как far, в противном случае такие подпрограммы рассматриваются как near.
Передача и возврат данных
Параметры передаются в стеке. Помещаются в стек в порядке, соответствующем порядку записи в тексте подпрограммы, т.е. последний в тексте будет на самом верху стека.
По умолчанию параметры передаются по значению, при наличии модификатора var – по ссылке, при этом размер указателя – far.
Скалярные и структурные данные, помещающиеся в байт, возвращаются в AL, помещающиеся в слово – в AX, помещающиеся в двойное слово – в паре DX:AX. Табл. 4 поясняет соответствие типов возвращаемых данных языка Pascal и регистров процессора.
Таблица 4
Тип функции | Регистр(ы) |
Boolean, Char, ShortInt, Byte | AL |
Integer, Word | AX |
LongInt | DX – старшее слово, AX – младшее |
Pointer | DX – сегмент, AX – смещение |
String | · в вызывающей подпрограмме резервируется память под возвращаемую строку; · в стек на самый низ (т.е. первым параметром) помещается адрес этой памяти; · вызываемая подпрограмма помещает по указанному адресу результат; · при возврате стек чистится от всех параметров, кроме этого адреса, удалением этого адреса должна заниматься вызывающая подпрограмма. |
Многомерные массивы располагаются в памяти таким образом, что быстрее изменяется последний индекс.
При передаче по значению массива, записи или строки компилятор формирует код, который обеспечивает передачу через стек far-адреса, выделение необходимой памяти в подпрограмме и копирование туда параметра.
Трансляция и компоновка
Для подключения внешней ассемблерной подпрограммы к программе на Pascal следует:
оттранслировать ассемблерную программу и получить ОМ;
в программе на Pascal описать внешнюю подпрограмму
procedure имя( параметры ); external;
в программу на Pascal с помощью команды {$L имяОМ } включить ОМ.
2.5. Соглашение о связях языка C (сводка)
Преобразование имен
Значащая длина идентификатора может быть от 8 до 250 символов, умолчание – 32. Для изменения служит команда Options+Compiler+Source.
Прописные и строчные буквы различаются.
В начало каждого имени включается символ подчеркивания, отменить это можно с помощью команды Options+Compiler+Advanced code generation.
Передача и возврат управления
Тип подпрограмм (near или far) и, следовательно, команд call и ret зависит от используемой модели памяти. Установка модели памяти осуществляется командой Options+Compiler+Code generation. Подробнее о моделях памяти см. лабораторную работу «Использование подпрограмм» настоящего сборника или документацию по СП.
Передача и возврат данных
Параметры передаются в стеке. Помещаются они в стек в порядке, обратном порядку записи в тексте программы, т.е. первый в тексте будет на самом верху стека.
Скалярные типы данных передаются по значению, массивы – по ссылке. Размер указателя (near или far) зависит от используемой модели памяти.
Скалярные и структурные данные, помещающиеся в байт, возвращаются в AL, помещающиеся в слово – в AX, помещающиеся в двойное слово – в паре DX:AX. Табл. 5 поясняет соответствие типов возвращаемых данных языка C и регистров процессора.
Таблица 5
Тип функции | Регистр(ы) |
char | AL |
short, int | AX |
long | DX – старшее слово, AX – младшее |
near * | AX – смещение |
far * | DX – сегмент, AX – смещение |
Многомерные массивы располагаются в памяти таким образом, что быстрее изменяется последний индекс.
При определении размеров структур и доступа к ним необходимо учитывать возможность выравнивания полей структур на границу слова (команда Options+Compiler+Advanced code generation).
Преобразование данных
При вызове подпрограммы скалярные данные типа float всегда преобразовываются в данные типа double. Поля типа float в структуре преобразованию не подвергаются.
Трансляция и компоновка
Модели памяти взаимодействующих подпрограмм должны быть согласованы. Этого можно достигнуть, либо установив одинаковые модели для C-компилятора (команда Options+Compiler+ Code generation) и ассемблера (директива model), либо указав явно модификаторы подпрограмм и параметров-указателей (атрибуты near или far).
Компоновка может быть выполнена в интегрированной среде Borland C++. В этом случае следует использовать файл проекта, в который включить ОМ или ИМ ассемблерной ПП. В первом случае потребуется только настройка компоновщика, во втором – и ассемблера.
При настройке компоновщика с помощью команды Options+Linker+Settings следует обязательно включить режим Case-sensitive link (различение прописных и строчных букв).
При настройке ассемблера с помощью команды Options+Transfer следует в список Program Titles внести ассемблер (он там наверняка уже будет) и правильно задать для него путь доступа (Program Path) и командную строку (Command Line), которая может выглядеть так – /MX /ZI $TASM. Здесь ключи задают, соответственно, для глобальных имен различать строчные и прописные буквы и включать полную отладочную информацию. Параметр $TASM обязателен.
Допустимо использование для компоновки непосредственно компоновщика TLINK, в этом случае в командной строке обязательно следует задать ключ различения строчных и прописных букв в именах – /c.
ПРИМЕР ВЫПОЛНЕНИЯ РАБОТЫ
В разделе приведен пример ассемблерной подпрограммы, выполняющей подсчет количества символов и количества строк (в смысле последовательность символов, завершающаяся \n) в строке (массиве символов), завершающейся нулевым байтом. Пример представлен в двух вариантах: с интерфейсом Pascal и C.
Интерфейс Pascal
Файл: COUNT.PAS
program Count;
{$L count.obj}
const StringToCount = 'Строка 1'+#10+'Строка 2'+#10+'Строка 3';
var
LCount : integer;
CCount : integer;
function LineCount(
StringToCount:string;
var CharacterCountPtr:integer):integer;external;
Begin
LCount := LineCount(StringToCount,CCount);
writeln('Стpок:',LCount);
writeln('Символов:',CCount);
End.
Файл: COUNT. ASM
;Действие:
; подсчет количества символов и количества строк (в смысле -
; последовательность символов, завершающаяся \n)
; в строке (массиве символов), завершающейся нулевым байтом
;
;Интерфейс:
; Borland Pascal, модель - small
; function LineCount(
; TestString:string;
; var CharacterCountPtr:integer):integer;external;
;
;Параметры и возвращаемые значения:
; StringToCount - указатель на строку, в которой выполняется подсчет
; CharacterCountPtr - указатель на переменную - количество символов
; возвращает - количество строк
;
NEWLINE equ 0Ah ;LF - символ новой строки
dosseg
model SMALL
codeseg
public LineCount
LineCount proc
push BP ;+пролог
mov BP, SP
push SI
push DS ;-пролог
xor CX, CX
mov DS,[BP + 10]
mov SI,[BP+8] ;DS:SI - указатель на длину входной строки
mov CL,[SI] ;счетчик символов
inc SI ;указатель на входную строку
xor DX, DX ;счетчик строк
xor BX, BX ;счетчик символов
LineCountLoop:
lodsb ;очередной символ входной строки в AL
and AL, AL ;а не нулевой ли это символ ?
jz EndLineCount ;да, конец входной строки
inc BX ;нет, увеличиваем счетчик символов
cmp AL, NEWLINE ;а не символ ли это новой строки ?
jnz EndLoop ;нет, продолжаем просмотр строки
inc DX ;да, увеличиваем счетчик строк
EndLoop:
loop LineCountLoop
EndLineCount:
cmp byte ptr [SI-2], NEWLINE ;есть ли в хвосте символ LF
je NoLastLine ;есть, не будем увеличивать счетчик строк
inc DX ;нет, будем увеличивать счетчик строк
NoLastLine:
mov CX, BX ;CX = BX сохраняем BX в CX
mov DS,[BP+6]
mov BX,[BP+4] ;DS:BX - указатель на счетчик символов
mov [BX],CX
mov AX, DX ;возвращаемое значение - счетчик строк
pop DS ;+эпилог
pop SI
pop BP
ret 8 ;-эпилог
LineCount ENDP
end
Интерфейс C
Файл: COUNT.CPP
/*
Файл:
COUNT.CPP
Действие:
Тестирование ассемблерной функции LineCount (файл: COUNT.ASM)
Модель: small
*/
#include <stdio.h>
char * TestString="Строка 1\nСтрока 2\nСтрока 3\n";
extern unsigned int LineCount(
char * StringToCount,
unsigned int * CharacterCountPtr );
void main()
{
unsigned int LCount;
unsigned int CCount;
LCount = LineCount(TestString, &CCount);
printf("Строк: %d\nСиволов: %d\n", LCount, CCount);
}
Файл: COUNT.ASM
;Файл:
; COUNT.ASM
;Действие:
; подсчет количества символов и количества строк (в смысле -
; последовательность символов, завершающаяся \n)
; в строке (массиве символов), завершающейся нулевым байтом
;Интерфейс:
; Borland C++ v.3.1, модель - small
; extern unsigned int LineCount(
; char * StringToCount,
; unsigned int * CharacterCountPtr);
;Параметры и возвращаемые значения:
; StringToCount - указатель на строку, в которой выполняется подсчет
; CharacterCountPtr - указатель на переменную - количество символов
; возвращает - количество строк
;
NEWLINE equ 0Ah ;LF - символ новой строки
dosseg
model SMALL
codeseg
public _LineCount
_LineCount proc
push BP ;+пролог
mov BP, SP
push SI ;-пролог
mov SI,[BP+4] ;DS:SI - указатель на входную строку
sub CX, CX ;счетчик символов
mov DX, CX ;счетчик строк
LineCountLoop:
lodsb ;очередной символ входной строки в AL
and AL, AL ;а не нулевой ли это символ ?
jz EndLineCount ;да, конец входной строки
inc CX ;нет, увеличиваем счетчик символов
cmp AL, NEWLINE ;а не символ ли это новой строки ?
jnz LineCountLoop ;нет, продолжаем просмотр строки
inc DX ;да, увеличиваем счетчик строк
jmp LineCountLoop
EndLineCount:
cmp byte ptr [SI-2], NEWLINE ;есть ли в хвосте символ LF
je NoLastLine ;есть, не будем увеличивать счетчик строк
inc DX ;нет, будем увеличивать счетчик строк
NoLastLine:
mov BX,[BP+6] ;BX - указатель на счетчик символов
mov [BX],CX ;
mov AX, DX ;возвращаемое значение - счетчик строк
pop SI ;+эпилог
pop BP
ret ;-эпилог
_LineCount ENDP
END
ВАРИАНТЫ ЗАДАНИЙ
Во всех заданиях следует разработать некоторую подпрограмму на ассемблере с интерфейсом Pascal или C и вызывающую программу, на соответствующем языке. Вызывающая программа должна демонстрировать работоспособность ассемблерной подпрограммы. Если в задании язык не указан, то можно выбрать любой.
1. Разработать подпрограмму на ассемблере, которая выполняет пересылку указанного числа байт. Адреса источника и приемника – параметры. Подпрограмма должна возвращать количество пересланных байт.
2. Разработать подпрограмму на ассемблере, которая выполняет обмен указанного числа байтов. Адреса областей памяти – операндов должны быть переданы как параметры. Подпрограмма должна возвращать количество перемещенных байтов.
3. Разработать подпрограмму на ассемблере, которая определяет и возвращает номер первого установленного бита в массиве байтов. Адреса массива и его размер должны быть переданы как параметры.
4. Разработать подпрограмму на ассемблере для определения длины строки. Адрес строки – параметр. Подпрограмма должна возвращать длину строки.
5. Разработать подпрограмму на ассемблере для сравнения строк (аналог функции strcmp языка C). Адрес строки – параметр. Подпрограмма должна возвращать длину строки. Язык – C.
6. Разработать подпрограмму на ассемблере для сравнения строк (аналог функции strcnmp языка C). Адрес строки – параметр. Подпрограмма должна возвращать длину строки. Язык – C.
7. Разработать подпрограмму, которая определяет, содержится ли одна заданная строка в другой заданной строке, и если да, то, начиная с какой позиции. Разработать программу, которая вводит с клавиатуры две строки и сообщает, содержится ли одна из них в другой и сколько раз. Язык – C.
8. Разработать подпрограмму, которая подсчитывает, сколько раз заданный символ встречается в строке. Разработать программу, которая вводит с клавиатуры строку, вводит число N и выдает список символов, которые встречаются в строке не менее чем N раз. Язык – C.
9. Разработать две подпрограммы, одна из которых соединяет две строки в одну, а другая обрезает строку до заданной длины (или дополняет пробелами, если длина строки меньше заданной). Разработать программу, которая вводит с клавиатуры число N, затем вводит несколько строк (конец ввода – пустая строка) и формирует новую строку, состоящую из первых N символов каждой введенной строки.
10. Разработать подпрограмму, которая разбивает заданную строку на две части: первое слово строки (до первого пробела) и остаток строки (пробелы после первого слова отбрасываются).
11. Разработать подпрограмму, которая определяет, содержится ли одна заданная строка в другой заданной строке, и если да, то, начиная с какой позиции. Язык – Pascal.
КОНТРОЛЬНЫЕ ВОПРОСЫ
1. Что означает понятие «соглашение о связях» ?
2. Каким образом осуществляется передача параметров по ссылке и по значению ?
3. Что такое «выравнивание полей структур на границу ...» ?
4. Каким образом осуществляется возврат значений в функциях ?
БИБЛИОГРАФИя
1. Сван Т. Освоение Turbo Assembler. К: Диалектика, 1996. 544 с.
2. Скэнлон Л. Персональные ЭВМ IBM PC и AT. М.:Радио и связь, 1989. 336с.
3. Брэдли Д. Программирование на языке ассемблера для персональной ЭВМ фирмы IBM. М.:Радио и связь, 1988. 448с.
4. Шнайдер А. Язык ассемблера для персонального компьютера фирмы IBM. М.:Мир, 1988. 406с.
5. Лю Ю-Чжен, Гибсон Г. Микропроцессоры семейства 8086/8088. Архитектура, программирование и проектирование микрокомпьютерных систем. М.:Радио и связь, 1987. 512с.
6. Нортон П. Персональный компьютер фирмы IBM и операционная система MS-DOS. М.:Радио и связь, 1991. 416с.
7. Mixed-Language Programming Guide. Document No. 410840031-500-R01-1287. Microsoft Corp., 1987.
Содержание
Введение......................................................................................................................... 3
Лабораторная работа № 1. Разработка и отладка программ на языке ассемблера 4
Лабораторная работа № 2. Программирование линейных конструкций. 13
Лабораторная работа № 3. Циклические и разветвляющиеся программы 16
Лабораторная работа № 4. Логические команды............................................ 19
Лабораторная работа № 5. Символьная обработка....................................... 22
Лабораторная работа № 6. Десятичная арифметика..................................... 28
Лабораторная работа № 7. Подпрограммы...................................................... 34
Лабораторная работа № 8. Использование подпрограмм на языке ассемблера в программах на языках C и PASCAL 47
Библиографя...............................................................................................................
Заметки
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
_________________________________________________________
Дроздов Сергей Николаевич
Калачев Дмитрий Петрович
Методическая разработка к лабораторным работам
«Программирование на языке ассемблера ПЭВМ IBM PC»
Ответственный за выпуск Калачев Д.П.
Редактор Кочергина Т.Ф.
Корректор Проценко И.А.
ЛР № 020565 Подписано к печати 5.12.97
Формат 60x84 1/16 Бумага офсетная.
Печать офсетная. Усл. п. л. – 3,6. Уч.-изд. л. – 3,0
Заказ № Тираж 300
«С»
Издательство Таганрогского радиотехнического университета
ГСП 17А, Таганрог, 28, Некрасовский, 44
Типография Таганрогского радиотехнического университета
ГСП 17А, Таганрог, 28, Энгельса, 1