Лабораторная работа № 3
(системное программирование и ОС)

Создание и использование библиотек объектных модулей.

Цель работы - изучить процесс создания и использования библиотек объектных модулей. Создать личную библиотеку объектных модулей.
(созданная Вами библиотека объектных модулей будет использоваться и пополнятся при выполнении следующих лабораторных работ).

(работа рассчитана на 4 - 6 час.)

Введение.

Технологически рациональнее часто используемые подпрограммы объединить в так называемый библиотечный файл или в библиотеку объектных модулей. Библиотеки объектных модулей могут содержать большое количество вспомогательных программных единиц. Очень часто подобные библиотеки объединяют в себе тематически однородные подпрограммы.

Кратко рассмотрим процесс получения (и загрузки для выполнения) загрузочного модуля.

1 шаг. Создают файл исходной программы (SOURCE файл). Обычно для этого применяют программу, называемую редактором текста (например EDIT имя_файла.ASM).

2 шаг. Транслируют исходную программу (файл), используя программу-ассемблер, и одновременно с получением распечатки программы на языке ассемблера (файл «листинг» - LST файл) помещают в файл полученную программу на машинном языке. Полученный таким образом файл представляет собой файл объектной программы (OBJ файл). Например можно использовать следующую командную процедуру
c:\tasm\bin\tasm.exe /c /r /la /ml /os /w2 /x /z /zi %1.asm,%1.obj,%1.lst

3 шаг. Связывают (или преобразовывают внутренний формат объектного файла) файл объектной программы с библиотечными программами и другими программами с помощью редактора связей, и таким образом формируют файл загрузочного модуля ( EXE файл) в такой форме, при которой сразу возможна его загрузка в оперативную память и выполнение. Например можно использовать следующую командную процедуру
C:\TASM\BIN\TLINK /m /M /s /l /i /Tde /v %1.obj,%1.exe,%1.map,MY_LIB.LIB;

4 шаг. Выполняют загрузочный модуль. Вызывают системный загрузчик, который копирует содержимое исполняемого файла в оперативную память ЭВМ и настраивает центральный процессор на выполнение машинных команд, содержащихся в загрузочном модуле.

Схема работы редактора текста, ассемблера, редактора связей.

В приведенном выше примере вызова редактора связей файл MY_LIB.LIB - файл библиотеки объектных модулей.

Создание файлов объектных модулей.

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

Рассмотрим пример:

Разработаем три вспомогательные подпрограммы:

display - для вывода символа из регистра dl,
kbin - для ввода с эхо сигналом одного символ в регистр al (при вводе ctrl-C - аварийное завершение ВСЕЙ программы),
crlf - для перевода курсора в следующую строку вывода
и поместим указанные подпрограммы соответственно в файлы display.asm, kbin.asm и crlf.asm.

Обратите внимание на то, что в каждом из указанных файлов имя подпрограммы и имя сегмента объявлено как public. Это указывает ассемблеру (и редактору связей) на возможность использования этого объектного файла, как файла содержащего обще доступную подпрограмму и сегмент. Указание extrn display : far служит для сообщения компилятору об использовании "внешней" подпрограммы. В начале каждой из подпрограмм выполняется сохранение используемых регистров, а перед выходом из подпрограммы - восстановление. Оператор языка программирования ассемблера SEGMENT так же требует дополнительного "внимания". С целью размещения всех подпрограмм и "главной" программы в одном сегменте оперативной памяти следует этот оператор кодировать с указанием служебного слова public. Подробнее об операторе SEGMENT можно посмотреть здесь.

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

Создадим и откомпилируем программу использующую разработанные подпрограммы - ppp.asm.

Обратите внимание на начало тестовой программы:

CODE SEGMENT 'CODE' PUBLIC
EXTRN display : far
extrn kbin : far
extrn crlf : far
ASSUME CS:CODE

Команда языка программирования ассемблеа - EXTRN служит для сообщения компилятору об использовании "внешней" подпрограммы. Вызов подпрограмм выполняется командами CALL.

call crlf
call crlf
mov dl,'П'
call display
mov dl,'р'
call display
Для получения загрузочного модуля программы ppp.asm необходимо с помощью редактора связей объединить все необходимые для работы программы ppp.asm объектные модули. Это можно сделать в командной строке при вызове редактора связей:

......>c:\TASM\BIN\TLINK /m /M /s /l /i /Tde /v ppp.obj+display.obj+crlf.obj+kbin.obj,ppp.exe,ppp.map;

или используя процедурный файл L1.bat

....>l1 ppp +display.obj+crlf.obj+kbin.obj

Создадим свою библиотеку объектных модулей и поместим в нее разработанные подпрограммы.

Работа с библиотекой объектных модулей.

В системе программирования Tasm для работы с библиотечными файлами может быть использована программа библиотекарь - TLIB.

Программа библиотекарь создает новую библиотеку и/или добавляет/заменяет в ней требуемый объектный модуль.
Типичное обращение к библиотекарю можно осуществить используя следующий процедурный файл lib.bat:

ECHO ON
c:\TASM\BIN\TLIb mylib.lib -+%1.obj, mylib.lst

В этом примере - - имя библиотечного файла, mylib.lst - файл протокола работы библиотекаря,
-+%1.obj - имя добавляемого/заменяемого объектного модуля.

Для создания библиотеки

mylib.lib и помещения туда созданных ранее объектных модулей необходимо выполнить:

lib display
lib crlf
lib kbin

Для сборки программы ррр с использованием библиотечного файла достаточно выполнить

......>c:\TASM\BIN\TLINK /m /M /s /l /i /Tde /v ppp.obj,ppp.exe,ppp.map,mylib.lib;

Или использовать процедурный файл LL.bat:

ECHO ON
c:\TASM\BIN\TLINK /m /M /s /l /i /Tde /v %1.obj%2,%1.exe,%1.map,mylib.lib;

выполнив
...>ll ppp

получим рабочую (загружаемую) программу.

Рассмотрим следующий пример.

Программа преобразования чисел в шестнадцатеричные символы

Для работы с табличными данными в системе команд предусмотрена команда xlatb (а также xlatw).

Если в регистре AL записано число n (0 <= n <= 255), то по команде xlatb оно замещается содержимым n-й позиции из специально подготовленной таблицы соответствий.

Если обозначить полученные в результате значения через а(n), то xlatb можно назвать командой преобразования п в а(п).

Эта команда удобна для преобразования кодов.

В качестве примера можно привести таблицу десятичных чисел n от 0 до 15 и соответствующих им шестнадцатеричных чисел а(n).

n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15
a(n) | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'

Ниже показана программа преобразования чисел n, представленных в ЭВМ в двоичной системе счисления, в n-е (по порядку) значения символов (чисел) от 0 до F.

code segment 'CODE' PUBLIC
assume cs:code
extrn display : far
main proc far
push ds
mov ax,0
push ax
mov ax,ddd
mov ds,ax
assume ds:ddd
mov si,0 ; начальное двоичное значение
mov cx,16 ; сколько раз увеличить и вывести
lea bx,table ; установка таблицы перекодировки
next: mov ax,si ; значение двоичного кода для перекодировки
xlatb ; собственно перекодировка.... в al
mov dl,al ; что выводим на консоль
call display
inc si
loop next
ret
main endp
code ends
ddd segment
table db '0123456789ABCDEF'
ddd ends
end main

(текст программы можно посмотреть здесь)

Рис. Программа преобразования двоичных чисел в шестнадцатеричные символы по команде xlatb.

Собственно преобразование осуществляется командой xlatb (translate byte), а вся программа работает по следующему алгоритму.

1. Провести подготовку к передаче управления MS-DOS.

2. Поместить содержимое DS (сегмента данных) в CS (сегмент кодов), так как область table находится в самой программе (в сегменте кодов).

3. Поместить начальное значение n, равное 0, в регистр SI, значение 16 в регистр СХ, а адрес первой позиции таблицы в регистр ВХ. Для выполнения команды xlatb необходимо, чтобы адрес начала таблицы обязательно находился в регистре ВХ. Это осуществляется по команде lea (load effective address). Вместо этой команды можно использовать команду

mov bx, offset table

Следует обратить внимание на то, что если вместо этой команды использовать команду mov bx, table, то в регистр ВХ будет введен не адрес table, а первые два байта из области table.

4. Далее переслать содержимое (n) регистра SI в регистр АХ (на самом деле для этого используется только правая половина (младшие байты) регистра, т.е. регистр AL), и по команде xlatb преобразовать n в а(n). Поскольку преобразованное значение формируется в регистре AL, переслать содержимое регистра AL в регистр DL и вывести на экран дисплея по команде call display.

5. По команде inc увеличить значение n на 1 в регистре SI. Затем по команде loop уменьшить значение регистра СХ на 1, и, если СХ <> 0, возвратиться по адресу next. В случае СХ = 0 закончить выполнение программы.

Команде xlatb аналогична команда xlatw (translate word). По этой команде производится преобразование данных длиной не 1 байт, а 2 байт. Действие этой команды ничем не отличается от действия команды xlatb, за исключением того, что вместо регистра AL используется регистр АХ. Необходимо обратить внимание на то, что в рассматриваемой программе значения n находятся в диапазоне 0 <= n <= 15. В противном случае (при n < 0 и n > 15) преобразование будет выполнено для данных, находящихся вне области table, и полученные в результате значения а(n) непредсказуемы.

Используя описанную выше программу легко составить библиотечную подпрограмму преобразования. Подобные подпрограммы очень удобны при организации вывода значений из оперативной памяти и регистров.

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

Данными, которые подвергаются преобразованию, являются 16 десятичных чисел: 15, 16, 17, .... 30, — последовательно формируемые в регистре SI (в программе main).

В подпрограмме преобразования hex после формирования содержимого регистра DS данные, находящиеся в регистре DX, помещаются в стек, и затем в регистр ВХ загружается значение начального адреса table; младшие 8 бит содержимого регистра DL пересылаются в регистр AL.

Затем, используя четыре команды shr, перемещают 4 старших бита в регистре AL на место 4 младших бит, по команде xlatb преобразуют их в шестнадцатеричное число и выводят на экран дисплея.

Затем по команде pop ax возвращают содержимое регистра АХ, ранее занесенное в стек по команде push dx, и выделяются младшие биты регистра AL по команде and с помощью маски — двоичного числа 00001111b.

Далее вновь выполняется преобразование в шестнадцатеричные символы (число).

Отметим, что в программе были использованы команды push/pop, в то время как указания адреса сегмента стека в ней не содержится. Это объясняется тем, что в данном случае используется стек, предусмотренный в ОС.

title d-hex.asm
code segment 'CODE' PUBLIC
assume cs:code
extrn display : far
main proc far
push ds
mov ax,0
push ax
mov ax,ddd
mov ds,ax
assume ds:ddd
mov si,0 ; начальное двоичное значение
mov cx,16 ; сколько раз увеличить и вывести
lea bx,table ; установка таблицы перекодировки
next: mov dx,si ; значение двоичного кода для перекодировки
Call hex ; собственно перекодировка и печать
mov dl,' ' ; печать разделителя
call display
inc si
loop next
ret
main endp
;---------------
hex proc
push dx
lea bx,table
mov al,dl ; первый полу байт
clc
shr al,1
shr al,1
shr al,1
shr al,1
xlatb
mov dl,al
call display
pop ax ; второй полу байт
and al,00001111b
xlatb
mov dl,al
call display
ret
hex endp
;============
code ends
ddd segment
table db '0123456789ABCDEF'
ddd ends
end main

(текст программы можно посмотреть здесь)

Рис. Программа преобразования десятичных чисел в двухразрядные шестнадцатеричные символы (числа).

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

Такой пример приведен ниже. Алгоритм работы этой программы следующий.

1. Вывести на экран дисплея символ ?.

2. Ввести с клавиатуры в регистр AL один символ, используя подпрограмму kbin.

3. Содержимое регистра AL также переслать в регистр АН. При этом в регистре АХ окажутся размещенными продублированные шестнадцатиразрядные данные.

4. Переслать содержимое регистра АХ в регистр SI, после чего отобразить на экране дисплея символ =.

5. С помощью подпрограммы hexw представить содержимое регистра DX, восстановленного из регистра SI, в вида четырехразрядного шестнадцатеричного числа.

В соответствии с подпрограммой hexw, которая используется на 5-м шаге этой программы, вначале содержимое регистра DH пересылается в регистр DL и на экран дисплея выводятся два старших разряда искомого числа, затем половина содержимого регистра DX, восстановленного из регистра DI (содержимое регистра DL), выводится на экран дисплея в качестве двух младших разрядов образовавшегося числа. Подпрограмма crlf используется для перемещения курсора в начало следующей строки. Если посмотреть на результат выполнения программы, то легко видеть, что код ASCII для введенных символов в шестнадцатеричной системе счисления представляется двумя одинаковыми парами символов.

           title d-hexw.asm
    code  segment  'CODE' public
           assume cs:code
           extrn display : far
           extrn kbin    : far
           extrn hex     : far
           extrn crlf    : far
    main   proc  far
           push  ds
           mov   ax,0
           push  ax

          mov  dl,'?'
          call display
          call kbin
          mov  ah,al
          mov  si,ax
          mov  dl,'='
          call display
          mov  dx,si
          call hexw
          call crlf
          jmp  main
    main  endp
    ;--------------------
    hexw  proc
          mov  di,dx
          mov  dl,dh
          call hex
          mov  dx,di
          call hex
          mov  dl,' '
          call display
          ret
    hexw  endp
    ;============
    code ends
         end main

(текст программы можно посмотреть здесь)

Рис. Программа преобразования двоичных чисел в четырехразрядные шестнадцатеричные символы (числа).

Более формальную информацию о подпрограммах (процедурах) можно посмотреть здесь.

Задание на лабораторную работу

1. Создайте в своей папке исходные модули подпрограмм display, crlf, kbin.

2. Создайте процедуры для работы с личной библиотекой объектных модулей.

3. Создайте свою библиотеку объектных модулей и поместите туда подпрограммы display, crlf, kbin.

4. Разработайте подпрограммы hex и hexw на основе приведенных выше примеров.

5. Выполните тестирование разработанных подпрограмм и поместите их в свою библиотеку объектных модулей.

6. Напишите тестовую программу, использующую разработанные подпрограммы, выполните ее отладку и тестирование.

7. Рассмотрите тестовую программу pp1.asm, разберитесь с ее назначением и выполните ее.

8. Разработайте на основе программы pp1.asm подпрограмму kbin2 для ввода по запросу двух символов с клавиатуры и помещения их в регистр AX.

9. Выполните отладку и поместите разработанную подпрограмму в свою библиотеку.

10. Перепишите программу pp1.asm с использованием подпрограммы kbin2.

11. Все листинги подпрограмм, программ и результатов тестирование поместите в отчет.

Контрольные вопросы

- что такое библиотека объектных модулей?

- как создать библиотеку объектных модулей?

- как использовать библиотеку объектных модулей?

- что содержит библиотека объектных модулей?

- зачем используются команды ассемблера - public и extern?

- использование команды xlatb

- вопросы по программам display, crlf, kbin hex hexw pp1 - основной алгоритм и команды.