На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 12 / Использование стандартных библиотечных программ Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Использование стандартных библиотечных программ

Если вы используете стандартный набор немодифицированных программ во всех Ваших программах, для Вас может оказаться полезным поместить эти стандартные программы в библиотечный файл, который всегда связан с Вашими программами. Использование этого метода упрощает процесс трансляции с ассемблера и редактирования связей, а также уменьшает размер исходных файлов вашей программы. Библиотечный файл создается путем трансляции файла, содержащего Ваши стандартные программы, и последующей обработки .OBJ - файла с помощью LIB - программы, помещенной на диске с макроассемблером MASM. В результате обработки LIB-программы получается файл, содержащий корректно отформатированную объектную программу с расширением .LIB. Внешние ссылки на эти стандартные программы должны быть описаны в исходном тексте данной программы, которая должна вызывать эти стандартные программы. Эти стандартные программы пишутся в формате:


EXTRN стандартная программа : расстояние


где EXTRN - управляющая команда, которая сообщает макроассемблеру MASM, что "стандартная подпрограмма" будет включаться во время редактирования связей либо из объектного файла, либо из библиотечного файла.


Параметр "расстояние" имеет значение или "близко" (near), или "далеко" (far) в зависимости от того, как была описана стандартная программа, на которую осуществляется ссылка. Для программ с расширением типа .COM параметр и расстояние всегда имеют значение "близко".


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


В листинге A-8 представлен полный исходный текст библиотечного файла STDLIB.LIB, о котором рассказывалось в предыдущих главах.


Листинг A-8. Исходный текст библиотечного файла
STDLIB.LIB
----------------------------------------------------------------
PAGE 60,132
TITLE   stdlib.asm/.ob ѓlib
.8086       ; позволяет только команды процессоров 8086/8088
.SALL       ; запретить распечатку макрорасширений
;- -  - - - - - - - - - - - - - - - - - - - - - - - - - -
;
;- - - - - - Равенства и макроопределения - - - - - - - -
;
INCLUDE stdmac.inc ; включить стандартные макробиблиотеки
 ; и равенства
;
;- - - - - - - - - - - Инициализация - - - - - - - - - -
;
; Инициализация, описанная ниже, представляет собой подм-
; ножество (и совместимое) с управляющей командой ".МОDEL
; SMALL" макроассемблера MASM версии 5.0 и выше.
;
_TEXT   SEGMENT WORD PUBLIC 'CODE'   ; сегмент программы
_TEXT   ENDS
;
_DATA   SEGMENT WORD PUBLIC 'DATA'   ; сегмент данных
_DATA   ENDS
;
DGROUP  GROUP   _DATA       ; определить группу сегментов
;
ASSUME  cs:_TEXT,ds:_DATA   ; назначить  физические сегменты
;
;
;********************************************************
; Начало библиотечных стандартных программ
;********************************************************
;
_TEXT   SEGMENT   ; начало сегмента текста программы
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Новая строка : отображает новую строку (возврат каретки +
;       + перевод строки)
;
; Вход : нет
;
; Выход :  AX и DX восстанавливаются;
; другие регистры не используются.
;
; Bызываемых стандартных программ: нет
;- - - - - - - - - - - - - - - - - - - - - - - - - -  - -
PUBLIC NEWLINE ; библиотечная  стандартная  программа
;
newline PROC    NEAR
        push    ax  ; сохранить содержимое регистров
        push    dx
;
        mov     dl,CR; отобразить возврат каретки
        mov     ah,02h
        @DosCall
        mov     dl,LF; отобразить перевод строки
        mov     ah,02h
        @DosCall
;;
        pop     dx   ; восстановить содержимое регистров
        pop     ax
        ret
;
newline ENDP
;
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++
;   CSAVE :  Выполняет автоматическое сохранение и
;   восстановление  содержимого  регистров : BX, CX, DI и
;   SI внутри вызываемой стандартной программы. Она вызы-
;   вается из  другой  вызываемой  стандартной  программы
;   следующим образом :
;
;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
; LOCALIZE       EQU   10h
; routine PROC   NEAR  ; FAR, если средняя, большая
;    ; или очень большая модель
;
;      push      bp
;      mov       bp,sp
;      sub       sp,LOCALIZE
;      call      csave
;      :
;      (текст стандартной программы)
;      :
;      ret ; всегда направляется в $cret
;
; routine ENDP
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;
; Вход : смотри описание выше
;
; Выход : смотри описание выше
;
; Используемые регистры: содержимое регистров BX, CX, DI и
;      SI сохраняется; регистры AX и DX
;      не трогаются.
;
; Вызываемые стандартные программы: идут обращения к
; "вызывающей" стандартной программе до тех пор, пока
; по ее команде возврата RET не осуществится возврат в
; эту программу, после чего по команде возврата RET
; этой программе осуществится возврат в исходную
; вызвавшую программу.
;
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PUBLIC   CSAVE       ; библиотечная стандартная программа
;
csave   PROC      NEAR
        push     bp     ; установить адресацию стека
        mov      bp,sp
        xchg     bx,[bp+2] ; сохранить содержимое регистров
; BX и получить адрес возврата
; вызвавшей стандартной программы
pop       bp  ; восстановить текущий адрес возврата
push      cx  ; сохранить содержимое остальных
     ; регистров
push      si
push      di
call      bx     ; продолжить обработку в
        ; вызвавшей стандартной программе
;
; Перейти  сюда по команде возврата RET вызвавшей
; стандартной программы
$cret:   pop       di       ; восстановить сохраненное
 ; содержимое регистров
pop       si
pop       sx
pop       bx
mov       sp,bp    ; cбросить локальные переменные
pop       bp
ret       ; aвозвращает в то место, куда
        ; обычно идет возврат по команде
    ; возврата RET в вызывающую программу
;
csave    ENDP
;
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++
; BIN2DEC -   Преобразование из двоичной в десятичную сис-
; тему  счисления. Отображает на экране дисплея в десятич-
; ном виде шестнадцатиразрядное число со  знаком  или  без
; знака. Находит самый последний разряд справа путем деле-
; ния.  Повторяет  до  тех пор, пока все не будет найдено.
; Может быть указано минимальное количество разрядов, под-
; лежащих отображению. Если минимальное количество указан-
; ных разрядов больше  фактического  количества  разрядов,
; результирующее число дополняется начальными нулями.
;
; Вход :   AX = число, подлежащее отображению
; CH = минимальное число разрядов, подлежащих
;       отображению
; DX = 0, если число, подлежащее обработке, не
;имеет знака или = 1, если число, под-
;лежащее обработке, имеет знак
;
; Выход : (регистры AX, CХ и DX восстанавливаются)
;
; Вызываемые стандартные программы: нет
;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
PUBLIC   BIN2DEC      ; библиотечная стандартная программа
;
bin2dec  PROC    NEAR
  push    ax     ; сохранить содержимое регистров
  push    bx
  push    cx
  push    dx
  mov     cl,0   ; очистить счетчик разрядов
  mov     bx,10  ; установить делитель = 10
  cmp     dx,0   ; всегда  отображать номер, как
        ; положительное число?
  je      more_dec        ; да, игнорировать проверку на
        ; отрицательное число
;
; Проверить на  отрицательное число. Если число
; отрицательное, сделать его положительным.
   or       ax,ax       ; число положительное ?
   jnl     more_dec     ; да, игнорировать "отрицательное"
   neg     ax  ; сделать число положительным
   @DisChr '-' ; отобразить знак "минус"
;
; Основной цикл деления - получить десятичный разряд.
; Повторять, пока остаются разряды.
more_dec:
xor     dx,dx       ; очистить
div     bx ; разделить на 10
push    dx ; сохранить остаток
inc     cl ; добавить к значению счетчика
  ; разрядов единицу
or      ax,ax       ; проверить  частное
jnz     more_dec    ; продолжить, если больше
;
; Основной цикл печати разрядов - обратный порядок.
sub     ch,cl       ; минимальное число разрядов
  ; получено?
jle     morechr     ; да, начать отображение
xor     dx,dx       ; нет, начать вставлять "нули"
morezero:
push    dx
inc     cl ; добавить к значению счетчика
  ; разрядов единицу
dec     ch ; проверить на совпадение
jnz     morezero    ; нет - продолжать вставку
morechr:
pop     dx ; восстановить последний разряд
add     dl,30h      ; преобразовать в код ASCII
@DisChr dl ; разряд результата
dec     cl ; вычесть из счетчика разрядов
  ; единицу
jnz     morechr     ; продолжить,  если больше
;
pop     dx    ; восстановить содержимое регистров
pop     cx
pop     bx
pop     ax
ret

;
bin2dec  ENDP
;
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++
; BIN2DEC2 - Преобразование из двоичной в десятичную систе-
;   му  счисления;  отображает  32-разрядное число. Создает
;   два десятичных числа, которые отображаются через  обра-
;   щения к BIN2DEC.
;       Может быть указано минимальное число разрядов, под-
;   лежащих  отображению.  Если минимальное количество ука-
;   занных разрядов больше фактического числа разрядов, вы-
;   ходное число дополняется начальными нулями.
;       Примечание:  сдвоенных регистров, содержащих число,
;   разбивается в лучшем случае, наименьшая значащая  часть
;   числа составляет 9.999. Оно никогда не будет отображено
;   как отрицательное число.
;
; Вход :   DX: AX = число, подлежащее отображению
; CH = минимальное число разрядов, подлежащих
;       отображению
;
; Выход : (регистры AX : DX восстанавливаются)
;
; Вызываемые стандартные программы: BIN2DEC (вывод
;   16-разрядного числа в десятичном виде)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
PUBLIC  BIN2DEC2    ; библиотечная стандартная  программа
;
bin2dec2 PROC    NEAR
;EXTRN  bin2dec2:NEAR   ; ссылка на стандартную программу
      ; BIN2DEC
push    ax     ; сохранить содержимое регистров
push    bx
push    cx
push    dx
;
;   Проверить на отрицательное число.  Если  отрицательное,
; сделать положительным.
or      dx,dx       ; число положительное ?
jnl     bd2_pos  ; да, игнорировать "отрицательное"
not     ax ; сделать число положительным
not     dx
add     ax,1        ; (точное) дополнение в двоич-
  ; ной системе счисления (допол-
  ; нительный код), реализуемое
  ; аппаратным способом
adc     dx,0
push    dx
push    ax
@DisChr '-'
pop     ax
pop     dx
;
; Теперь разбить число, подлежащее распечатке, на две
; управляемые части.
bd2_pos:
mov     bx,10000    ; установить делитель = 10000
div     bx ; разбить число  на пары
cmp     dx,0        ; отбросить, если наибольшее
je      bd2_2big    ; значащее число слишком велико
or      ax,ax       ; выяснить, равно ли "0"
  ; наибольшее значащее число
jz      bd2_nosig   ; нет наибольшего значащего
  ; числа
;
;  Печать первого наибольшего значащего числа (старшая
;  часть числа).
      push    dx
      sub     ch,4        ; четыре разряда будут распе-
        ; чатаны из наименьшей значащей
        ; части  числа
      jnc     bd2_cntok   ; запросить больше 4 для того,
        ; чтобы значение счетчика стало
        ; действительным
      mov     ch,0        ; в противном  случае, опрос идет
   ; до тех пор, пока не кончатся разряды
bd2_cntok:

call    bin2dec     ; печатать наибольшую значащую
  ; часть числа
pop     dx ; восстановить наименьшую
  ; значащую часть числа
mov     ch,4        ; четыре разряда в наименьшей
  ; значащей части числа
;
; Печатать наименьшую значащую часть числа (младшую часть
; числа).
bd2_nosig:
mov     ax,dx       ; печатать сначала содержимое
  ; регистра DX (наименьшую зна-
  ; чащую  часть числа)
call    bin2dec     ; печатать наименьшую значащую
  ; часть числа
bd2_done:
pop     dx ; восстановить содержимое регист-
  ; ров и выйти из программы
pop     cx
pop     bx
pop     ax
ret
bd2_2big:
@DisStr  Bin2BigErrMsg
jmp     short bd2_done   ; возвратиться из стан-
       ; дартной программы
;
_TEXT    ENDS
_DATA    SEGMENT
Bin2BigErrMsg db "BIN2DEC2 error: Oшибка: число слишком
       велико.$"
_DATA    ENDS
_TEXT    SEGMENT
;
bin2dec2 ENDP
;
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
; BIN2HEX  -  Преобразование из двоичной в  шестнадцатирич-
; ную  систему  счисления;  отображает 16-разрядное число в
; шестнадцатиричном виде.
;       Может быть указано минимальное количество разрядов,
; подлежащих отображению : если минимальное число указанных
; разрядов  больше фактического количества разрядов, выход-
; ное число дополняется значащими нулями.
;
; Вход :   AX = число, подлежащее отображению
; CH = минимальное число разрядов, подлежащих
;      отображению (от 1 до  4).
;      Если CH=0, то значение счетчика разря-
;      дов по умолчанию принимается равным 4)
;
; Выход : нет (регистры AX и CX восстанавливаются)
;
; Вызываемые стандартные программы: нет
;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
PUBLIC BIN2HEX    ; библиотечная стандартная программа
;
bin2hex  PROC     NEAR
push     ax   ; сохранить содержимое регистров
push     bx
push     cx
push     dx
;
    mov      bx,ax        ; использовать регистр BX для
        ; временного хранения
    cmp      ch,0; счетчик уже установлен?
    jne      align_left   ; да, тогда продолжать
    mov      ch,4; иначе, установить значение
        ; счетчика символов, равным 4
;
; Выровнять число по левому краю регистра AX (циклически
; сдвигать влево на (4 - CH) х 4 битовые позиции
allign_left:
      mov      cl,4   ; определить число сдвигаемых цифр
      sub      cl,ch
      shl      cl,1   ; умножить на 4
      shl      cl,1
      rol      bx,cl        ; выравнивание влево
      mov      cl,4; и установить наименьшее
      ; значение счетчика циклического сдвига
;
; Основной  цикл повторить  N раз. Печатать старший разряд.
more_hex:
rol      bx,cl        ; переместить на один разряд
    ; вправо
mov      al,bl        ; переслать в регистр AL
and      al,0Fh       ; только младший разряд
add      al,90h       ; скрытое преобразование в
daa ; шестнадцатиричные символы
    ; в коде ASCII
adc      al,40h
daa
;
; Отобразить разряд
@DisChr  al
dec      ch       ; вычесть из счетчика разрядов
; единицу
jnz      more_hex ; продолжить, если больше
;
pop      dx   ; восстановить содержимое регистров
pop      cx
pop      bx
pop      ax
ret
;
bin2hex ENDP
;
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
; CHGCASE   -    Изменить  регистр  клавиатуры для симво-
; лов. Меняет регистр символов в коде ASCII. Указывается
; тип преобразования регистра клавиатуры.
;
;  1. Принудительное изменение верхнего  регистра  клавиатуры
;     на нижний.
;  2. Принудительное изменение нижнего регистра клавиатуры на
;     верхний.
;  3. Изменить состояние регистра клавиатуры на противополож-
;     ное (если нижний, то верхний; если верхний, то нижний).
;
; Вход :   AL = буквенный символ в коде ASCII, подлежащий
;      преобразованию
; AH = тип преобразования:
;      "L" или "l" = печать символа на нижнем
;  регистре клавиатуры
;      "U" или "u" = печать символа на верхнем
;  регистре клавиатуры
;      любое другое значение меняет состояние
;      регистра клавиатуры на противоположное
;
; Выход :  AL = преобразованный  символ в коде ASCII
; AH = состояние символа:
;      "L" = нижний регистр
;      "U" = верхний регистр
;      0 = если символ в регистре AL не являлся
; буквенным символом в коде ASCII
;      Содержимое всех других регистров
;      восстанавливается
;
; Вызываемые стандартные программы: нет
;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
PUBLIC  CHGCASE   ; библиотечная стандартная программа
;
chgcase PROC      NEAR
        push      dx    ; сохранение содержимого регистров
;
; Определить, содержит ли регистр AL буквенный символ в коде
; ASCII, и если символ действителен, определить его регистр.
    cmp       al,"A"       ; находится символ под первой
; буквой верхнего регистра?
    jl        error        ; да, он не является буквенным
; символом в коде ASCII
    cmp       al,"Z"       ; находится символ под последней
; буквой верхнего  регистра?
    jle       is_upper     ; да, символ соответствует
; верхнему регистру
    cmp       al,"a"       ; находится символ под первой
; буквой нижнего регистра?
    jl        error        ; да, он не является буквенным
; символом  в  коде ASCII
    cmp       al,"z"       ; находится символ под последней
; буквой нижнего регистра?
    jle       is_lower     ; да, символ находится в нижнем
; регистре
    jmp       short error  ; в противном случае, он не являет-
; ся буквенным символом в коде ASCII
;
is_upper:
    mov       dl,"U"        ; пометить символ как признак
 ; верхнего регистра
    jmp       short convert_type ; и продолжить
is_lower:
     mov      dl,"L"        ; пометить символ как признак
 ; нижнего регистра
     jmp      short convert_type ; и продолжить
error:
     mov      ah,0   ; пометить символ как не буквенный
   ; символ  в  коде  ASCII
     jmp      short done  ; и завершить выполнение процедуры
;
convert_type:
     cmp      ah,"l"     ; изменить  на  нижний регистр?
     je       to_lower   ; да, поэтому изменить символ
     cmp      ah,"L"     ; изменить  на  нижний регистр?
     je       to_lower   ; да, поэтому изменить символ
     cmp      ah,"u"     ; изменить  на  верхний регистр?
     je       to_upper   ; да, поэтому изменить символ
     cmp      ah,"U"     ; изменить  на  верхний регистр?
     je       to_upper   ; да, поэтому изменить символ
;
;    В противном случае, изменить регистр клавиатуры
;    на противоположный
   cmp      dl,"L"      ; это символ нижнего регистра?
   je       to_upper    ; да, изменить его на верхний регистр
 ; в противном случае, это верхний  регистр,
 ; поэтому сделать его нижним
;
to_lower:
    mov      ah,"L"     ; установить признак регистра для
      ; возврата
    cmp      dl,ah      ; символ уже соответствует нижнему
      ; регистру?
    je       done       ; да, действие выполнено
    add      al,20h     ; в противном случае, изменить на
      ; нижний регистр
    jmp      short done ; и выйти из процедуры
;
to_upper:
    mov      ah,"U"   ; установить признак регистра для возврата
    cmp      dl,ah    ; символ уже соответствует верхнему
    ; регистру ?
    je       done     ; да, действие выполнено
    sub      al,20h   ; в противном случае, изменить на
    ; верхний  регистр
;
done:
pop      dx  ; восстановить содержимое регистров
ret
;
chgcase  ENDP
;
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
; DOSVER -  Получает версию операционной системы MS-DOS
; и  возвращает старшую и младшую версии. Возвращает значе-
; ние "1.00", если текущая версия DOS 1.00 или 1.10.
;
; Вход :   нет
;
; Выход :  AL = старшая версия
; AH = младшая версия ( =  00,  если  перед этим
;      была  версия 2.00 DOS)
;       (Содержимое всех других регистров восстанавливается)
;
; Вызываемые стандартные программы: нет
;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
PUBLIC  DOSVER       ; библиотечная стандартная программа
;
dosver    PROC    NEAR
 push    bx      ; сохранить содержимое регистров
 push    cx
 push    dx
;
 xor     ax,ax    ; очистить регистр AX
 mov     ah,30h    ; загрузить функцию "получить
 ; версию DOS"
 @DosCall
 cmp     al,0      ; это версия предыдущая 2.00?
 jg      dos2plus  ; нет, действие сделано
 mov     al,1    ; в противном случае это версия 1.ХХ
 mov     ah,0    ; установить младшую версию в "00"
;
dos2plus:
 pop     dx      ; восстановить содержимое регистров
 pop     cx
 pop     bx
 ret
;
dosver    ENDP
;
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
; DOSV2CON: Получает и отображает текущую версию операцион-
; ной системы MS-DOS, и возвращает версию  вызывающей  прог-
; рамме.
;
; Вход :   нет
;
; Выход :  AL = старшая версия
; AH = младшая версия
;       (Содержимое всех других регистров восстанавливается)
;
; Вызываемые стандартные программы:
;        DOSVER  (получает версию MS-DOS)
;        BIN2CON (отображает номера в десятичном виде)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
PUBLIC DOSV2CON    ; библиотечная стандартная  программа
;
dosv2con   proc   NEAR
;;
;EXTRN  dosver: NEAR    ; получить  версию MS-DOS
;EXTRN  bin2dec: NEAR   ; отображает номера в десятичном виде
;
       push   bx      ; сохранить  содержимое  регистров
       push   cx      ;
       push   dx      ;
;
       call   dosver  ; получить  версию MS-DOS
       push   ax      ; сохранить возвращенную версию
       push   ax      ; и сохранить ее снова
       xor    ah,ah   ; записать номер старшей версии в
    ; регистр AL
       mov    ch,1    ; отобразить по крайней мере 1 разряд
       call   bin2dec ; вывести  на  печать число
       @DisChr '-'    ; символ-разделитель
       pop    ax      ; восстановить номер младшей версии
       cmp    al,1    ; это версия 1.ХХ?
       je     ver1xx  ; да, отобразить "ХХ" как младшую версию
       xchg   ah,al   ; в противном случае поместить номер
    ; младшей версии в регистр AL
       xor    ah,ah   ; очистить верхние
       mov    ch,2    ; отобразить, по крайней мере, 2 разряда
       call   bin2dec ; вывести число
       jmp    short end_ver      ; конец
;
ver1xx:
  @DisChr 'X'   ; вывести "Х"
  @DisChr 'X'   ; и опять
;
end_ver:
  pop      ax   ; восстановить  номер версии для воз-
       ; врата основной стандартной программе
  pop      dx   ; восстановить остальные регистры
  pop      cx
  pop      bx
  ret
;
dosv2con   ENDP  ; конец  стандартной  программы
;
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
; MEMALLOC - Распределяет  блок памяти указанного размера
; в параграфах (16 байт).
;
; Вход :  BX = размер запрашиваемого блока в 16-байтных
;     параграфах
;
; Выход : Признак  переноса  = 0, если УСПЕХ, причем
;        AX = адрес сегмента распределенного
;    блока памяти
;        (Содержимое  регистра BX восстанавливается)
;Признак переноса = 1, если ОТКАЗ,  причем
;        AX = код ошибки,
;    7 = разрушенные блоки управления памятью
;    8 = недостаточная память
;        BX  = наибольший доступный блок памяти в
;     параграфах
;
; Вызываемые стандартные программы: нет
;- -  - - - - - - - - - - - - - - - - - - - - - - - - - -
PUBLIC MEMALLOC   ; библиотечная стандартная  программа
;
memalloc  PROC      NEAR
 push      bp        ; сохранить указатель базы
 push      bx        ; сохранить содержимое регистра BX
 mov       bp,sp     ; инициализировать указатель базы
;
 xor       al,al     ; очистить регистр AL
 mov       ah,48h    ; загрузить функцию распределения
   ; памяти
 @DosCall   ; выполнить распределение памяти
 jnc       end_memalloc     ; завершить выполнение,
   ; если нет ошибки с адресом
   ; сегмента в регистре AX
; в  противном случае, завершить
; выполнение с установкой признака
;  переноса
 mov       word ptr [bp],bx ; максимальным размером
   ; блока  (в  регистре BX)
   ; и кодом ошибки в регистре AX
;
end_memalloc:
 pop       bx       ; восстановить регистр BX
 pop       bp       ; восстановить указатель базы
 ret
;
memalloc ENDP
;
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
; MEMSIZE:  Изменяет размер блока памяти,  ранее  распреде-
; ленной  с помощью стандартной программы MEMALLOC. Указыва-
; ются адрес блока и запрашиваемый размер (в 16-байтных  па-
; раграфах).
;
; Вход :  ES = адрес сегмента распределенного блока памяти
;BX = новый размер в 16-байтных параграфах
;
; Выход : Признак  переноса  = 0, если УСПЕХ, причем
;   (Содержимое  всех регистров восстанавливается)
;Признак переноса = 1, если ОТКАЗ,  причем
;        AX = код ошибки,
;    7 = разрушенные блоки управления памятью
;    8 = недостаточная память
;    9 = недействительный адрес блока
;        BX  = наибольший доступный блок памяти в
;     параграфах, если AX = 8,
;     в противном случае, содержимое его
;     восстанавливается.
;       (Содержимое регистра ES восстанавливается)
;
; Вызываемые стандартные программы: нет
;- - - - - - - - - - - - - - - - - - - - - - - - - - -
PUBLIC   MEMSIZE   ; библиотечная стандартная  программа
;
memsize  PROC       NEAR
push       bp   ; сохранить указатель базы
push       es   ; сохранить адрес блока памяти
push       ax   ; сохранить регистр AX
push       bx   ; сохранить регистр BX
mov        bp,sp  ; инициализировать указатель базы
;
xor        al,al   ; очистить регистр AL
mov        ah,4Ah  ; загрузить функцию и изменить
 ; размер блока
@DosCall
jnc        end_memsize       ; завершить выполнение,
  ; если нет ошибки
 ; в противном случае, завершить выполнение
 ; с установкой признака  переноса
pushf      ; сохранить признаки
cmp        ax,8     ; памяти недостаточно?
jne        memsize_err       ; нет, продолжить
mov        word ptr [bp],bx  ; в противном случае,
   ; сохранить максимально доступный размер
memsize_err:
mov        word ptr [bp+2],ax ; сохранить код ошибки
popf        ; восстановить  признаки
;
end_memsize:
pop        bx   ; восстановить содержимое регистров
pop        ax
pop        es
pop        bp   ; восстановить указатель базы
ret
;
memsize  ENDP
;
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++
; MEMFREE - Освобождает  блок памяти, ранее распределенный
; стандартной программой MALLOC.
;
; Вход :  ES = адрес сегмента распределенного блока памяти
;
; Выход : Признак  переноса  = 0, если УСПЕХ
;       (Содержимое регистра ES восстанавливается)
;Признак переноса = 1, если ОТКАЗ,  причем
;        AX = код ошибки,
;    7 = разрушенные блоки управления памятью
;    9 = недействительный адрес блока
;       (Содержимое регистра ES восстанавливается)
;
; Вызываемые стандартные программы: нет
;
;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
PUBLIC MEMFREE     ; библиотечная стандартная  программа
;
memfree  PROC       NEAR
push       bp     ; сохранить указатель базы
push       es     ; сохранить адрес блока памяти
push       ax     ; сохранить регистр AX
mov        bp,sp  ; инициализировать указатель
; базы
xor        al,al  ; очистить регистр AL
mov        ah,49h ; загрузить функцию осво-
; бождения памяти
@DosCall    ; выполнить освобождение памяти
jnc        end_memfree     ; завершить выполнение,
; если нет ошибки
      ; в противном случае, завершить выпол-
      ; нение с установкой признака переноса
mov   word ptr [bp],ax ;  и кодом ошибки (регистр AX)
;
end_memfree:
pop        ax   ; восстановить содержимое регистра AX
pop        es   ; восстановить адрес блока
pop        bp   ; восстановить  указатель базы
ret
;
memfree  ENDP
;
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; MERRHNDL - Обработка ошибки распределения памяти/ос-
; вобождения памяти (повторного задания размера).
;
; Вход :  AX = код ошибки
;BX  = наибольший доступный блок памяти
;     (если код ошибки = 8)
;ES = адрес сегмента распределенного блока памяти
;     (если код ошибки = 9)
;
;ES = адрес сегмента распределенного блока памяти
;
; Выход : нет (содержимое всех регистров восстанавливается)
;
; Вызываемые стандартные программы:
;        BIN2CON (отображает номера в десятичном виде)
;- - - - - - - - - - - - - - - - - - - - - - - - - -  - -
PUBLIC  MERRHNDL       ; библиотечная стандартная  программа
;
merrhndl PROC      NEAR
;
        cmp        ax,7   ; очищены блоки управления памятью?
        jne        mem_error8       ; нет, продолжить проверку
        @DisStr    TrashedMemErr_Msg; да, завершить выполнение
; сообщением
        ret       ; вернуться
;
mem_error8:
        cmp        ax,8    ; памяти  недостаточно?
        jne        mem_error9       ; нет, продолжить проверку
        @DisStr    InsuffMemErr_Msg ; да, завершить выполнение
; сообщением
        @DisNum    bx,10,1,0   ; и наибольшим доступным блоком
    ; памяти
        @Newline      ; отобразить пустую строку
        ret  ; вернуться
;
mem_error9:
        cmp        ax,9    ; адрес блока памяти
; недействителен?
        jne        mem_err_unknown  ; нет, неизвестна причина
        @DisStr    IncorrSegAddr_Msg; отобразить сообщение об
; ошибке
        @DisNum    es,16,4      ; отобразить адрес  сегмента
        @NewLine       ; отобразить пустую строку
        ret   ; вернуться
;
mem_err_unknown:
        @DisStr   UnknownMemErr_Msg ; вывести сообщение
        ret
;
_TEXT   ENDS   ; конец сегмента текста программы
_DATA   SEGMENT; начало сегмента данных
trashedMemErr_Msg db  ""Сбой при распределении памяти: управ-"
db "ляющие блоки памяти разрушены.",CR,LF,"$"
InsuffMemerr_Msg  db ""Сбой при  памяти: "
db "Недостаточно памяти",CR,LF
db "наибольший доступный блока памяти = $"
IncorrSegAddr_Msg db "Неправильный адрес сегмента для "
     db "повторного задания размера/освобождения.",CR,LF
db "Адрес сегмента = $"
UnknownMemErr_Msg db "Неизвестная ошибка при распределении/"
db "повторном задании размера/освобождении "
db "памяти.",CR,LF,"$"
_DATA    ENDS   ; конец сегмента данных
_TEXT    SEGMENT; начало сегмента программы
;
merrhndl ENDP
;
;
;********************************************************
;  Конец стандартных библиотечных программ
;********************************************************
_ТEXT    ENDS
END
----------------------------------------------------------------

Как видно из листинга, все стандартные программы должны быть описаны в исходном файле как PUBLIC (общего пользования) с тем, чтобы сделать их доступными для других программ. Любая метка (которая представляет собой то же, что и имя стандартной программы), подлежащая использованию в других программах, должна быть описана таким образом.


Если стандартные программы должны включаться в .EXE-файлы, то единственное что необходимо - это использовать управляющую команду EXTRN, помещенную "за пределами описания сегмента". Редактор связей LINK находит данную ссылку в библиотеке и помещает стандартную программу, на которую идет ссылка в ее собственный сегмент в окончательной программе. Однако, если эти стандартные программы должны включаться в файлы типа .COM, то оба имени и сегмента и "класса", используемые для .COM - программы, должны соответствовать именам, используемым в стандартной библиотечной программе.


Чтобы использовать стандартные программы BIN2DEC или BIN2НEХ программа типа .COM должна использовать следующее описание сегмента:


   code     segment para public "code"

Отметим, что описание данного сегмента должно быть определено как PUBLIC. В этом случае и имя сегмента (code) и имя класса ('code') одинаковы, чтобы облегчить их запоминание. Кроме того управляющие команды EXTRN должны быть помещены в описание сегмента, что позволит макроассемблеру MASM знать, какие внешние стандартные программы являются составной частью этого сегмента. (Метки PUBLIC и EXTRN даются атрибутам того же сегмента, что и сегмента, который включает их описания).


Дополнительная информация относительно библиотечных стандартных программ, меток PUBLIC и EXTRN можно найти в справочных руководствах по макроассемблеру MASM и редактору связей LINK фирмы "Майкрософт".


НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz