Сделать приведенную программу резидентной (FASM) - Assembler

Узнай цену своей работы

Формулировка задачи:

Всем доброго времени суток! Нужно сделать программу резидентной. Помогите кто чем сможет.
use16 ; генерация 16-битного кода
org 100h ; отступаем 256 байт от начала памяти 
char db 65 ; аски код начального символа т.е. А
kpos dw 0 ; переменная для сохранения позиции курсора (изначальная позиция курсора (т.е. левый верхний угол)
jmp start
 
install:  
        pushf ; перед выполнением процедуры сохранение флаги
        push    ds es ax di bx cx ; сохранение регистров в стек
       
  mov ax,0B800h ; загружаем в 16-битный регистр данных, 0b800h соответствует сегменту дисплея в тестовом режиме
  mov es,ax ;т.к. загрузка числа напрямую в сегментный регистр запрещена
  mov di,[kpos] ; смещение относительно сегмента 0b800h (т.е. позиция курсора на экране)
  mov cx,1 ; в сх длина сообщения т.е. количество выводимых символов
  mov al,[char] ; в al заносится  аски код символа 
m1:
 mov ah,00001111b ;заносим цвет символа и фона в двоичном коде
                            ; где 7 бит- мерцание символа, 6-4 - цвет фона, 3-яркость символа,2-0-цвет символа
  mov [es:di],ax ;заносим по адресу 0b800h:0000h атрибут символа и ASCII-код символа
 add di,2 ; смещаемся на 2 байта  чтобы переместить курсор на след. позицию на экране
   inc al ; увеличиваем аски-код символа на 1, чтобы перейти к след. символу по алфавиту
   cmp al,91 ; сравнение аски кода полученного символа с аски кодом символа не нужного для вывода на экран (т.е. с аски кодом знака а не буквы)
   jnz m3 ; пока al не равно 91 то переход на метку m3
   mov al,97 ; в al заносится аски код маленькую буквы а
   m3: 
   cmp al,123 ; проверка совпадает ли аски код с аски кодом маленькой буквы z (т.е. последний символ английского алфавита)
   jnz m2  ; пока al не равно 123 то переход на метку m2
   mov al,65  ; если в al  аски код маленькой буквы z то заносим в al аски код буквы A
      m2:
      cmp di,320 ; проверка находится ли курсор в конце второй строки 
      jnz m4 ; если di не равно 320 то переход на метку m4
      mov di,0 ; так как di равно 320 то в di  заносится 0 (чтобы перейти на начало первой строки)
      m4:
      mov [kpos],di ; сохранение позиции курсора
        mov     [char],al ; сохранение аски кода символа
        loop m1  ;цикл метки m1
        pop     cx bx di ax es ds  ; выносим из стека значения сохраненных ранее регистров
        popf ; востанавливаем значения флагов
        db      0eah            ;переход на старый обработчик
old08 dw      ? ;переменная для старого вектор прерывания
old_seg dw      ?  ; переменная старого сегмента прерывания
 
start:
 mov ax,03h    ;функция установки текстового видеорежима
    int 10h
        mov     ax, 3508h     ; заносим в ax функцию получения вектора прерывания (адреса подпрограммы)
        int     21h ; получаем вектор 09h(нажатие на клавиатуру), после выполнения прерывания в bx заносится вектор , а в es  сегмент вектора
        mov [cs:old08], bx ; сохраняем вектор
        mov     [cs:old_seg], es ; сохраняем сегмент вектора
 
        mov     ax, 2508h       ; устанавливаем свой ветор
        mov     dx, install   ;указываем адрес процедуры которая будет выполнятся вместо подпрограммы прерывания 1Ch 
        push    cs ;заносим в стек сегмент кода
        pop     ds ; выносим из стека сегмент кода в сегмент данных
        int     21h ; выполняем установку ветора с новой процедурой
 
  key:
        xor     ax, ax ; обнуляем ах
        int     16h ; прерывание сервиса клавиатуры после которого в al заносится аски код нажатой клавиши
        cmp     al, 27 ; проверка нажата ли кнопка ESC
        jne     key  ; пока не нажата клавиша ESC переход на метку getkey 
 
        mov     ax, 2508h       ; восстанавливаем старый вектор, для этого
        mov     dx, [cs:old08] ; в dx заносится адрес подпрограммы старого (сохраненного) вектора
        mov     ds, [cs:old_seg] ; в ds заносится старый сегмент вектора
        int     21h ; выполняем установку ветора со старой процедурой

        mov     ax, 4C00h ; передача управления операционной системе
        int     21h
коменты могут быть не совсем корректными

Решение задачи: «Сделать приведенную программу резидентной (FASM)»

textual
Листинг программы
use16           ;16-битный режим
org 100h        ;смещение програмы в памяти (com-файл)
Begin:  jmp InstallTSR  ;Загрузка резидента в память
Old08   dd ?        ;резервируем место для адреса оригинального обработчика прерывания 08h
cnt db 90
col db 0
New08Obrab:     ;новый обработчик прерывания int08h
    jmp short cont
    dw 0fffeh       ;метка присутствия резидента в памяти
cont:   pushf           ;заносим флаги в стек, поскольку iret в конце оригинального обработчика заберет один экземпляр флагов из стека
    call dword [CS:Old08]   ;вызов оригинального обработчика
    cli         ;запретить прерывания
    push ax         ;сохранить регистры общего назначения
    push bx
    push es
    mov ax,0b800h       ;еs настраивается на видеопамять
    mov es,ax
    cmp [cs:cnt],0      ;если счетчик не равен 0
    jnz fin08       ;то закончить прерывание
    mov [cs:cnt],90     ;если 0, занести в счетчик значение эквивалентное 5 сек
m1: add [cs:col],10h    ;изменить цвет н а следующий
    cmp [cs:col],80h    ;если не 80h
    jnz m2          ;то пропустить
    mov [cs:col],0      ;сбросить цвет фона
m2: mov al,[es:1]       ;взять цвет символа в верхнем левом углу
    shl al,4        ;сдвинуть его в фон
    cmp [cs:col],al     ;если текущий цвет фона будет сливаться с символами
    jz m1           ;то изменить цвет
    xor bx,bx       ;начало верхней строки видеопамяти
lp: and [es:bx+1],byte 0fh  ;сбросить фон символа на экране
    mov al,[cs:col]     ;взять цвет фона
    or [es:bx+1],al     ;записать в видеопамять
    add bx,2        ;перейти к следующему символу
    cmp bx,160      ;пока не закончится строка экрана
    jb lp           ;продолжать
fin08:  dec [cs:cnt]        ;уменьшить счетчик
    pop es          ;восстанавливаем регистры
    pop bx
    pop ax
    sti         ;разрешить прерывания
    iret            ;выход из прерывания
InstallTSR:         ;загрузка резидента
    mov ax, 3508h
    int 21h         ;получить адрес обработчика
    mov dx, word [es:bx+2]  ;взять сигнатуру
    cmp dx, 0fffeh      ;если не загружен
    jnz not_loaded          ;то продолжаем
    call isunload       ;проверить нет ли ключа выгрузки
    test al,al      ;если есть
    jnz unload      ;то выгружаем
    ;иначе выводим сообщение, что загружен
    mov dx,already      ;адрес строки
    mov ah,09h      ;функция вывода строки на экран
    int 21h         ;выводим на экран
ex: mov ah,4ch      ; стандартный выход из программы
    int 21h
not_loaded:
    call isunload       ;проверить нет ли ключа выгрузки
    test al,al      ;если есть
    jnz ex          ;то не загружаем
    cli
    mov word [Old08],BX ;сохранить вектор прерывания
    mov word [Old08+2],ES
    mov ax,2508h        ; SetVector
    mov dx,New08Obrab
    int 21h         ;установить новый обработчик прерывания
    sti
    ; сообщение об успехе
    mov dx,Success      ;адрес строки
    mov ah,09h      ;функция вывода строки на экран
    int 21h         ;выводим на экран
 
    mov ax,3100h    ; KeepProc
    mov dx,(InstallTSR-Begin+10Fh)/16; указываем системе сколько памяти в параграфах занимает наш резидент
    int 21h     ; закончить, но остаться в памяти
unload: ;выгрузка
    cli
    mov ax,2508h    ; функция установки вектора 08h
    lds dx,[es:Old08] ;в ds:dx адрес старого обработчика (Из копии в памяти!!!)
    int 21h     ;возврашаем старый обработчик
    sti
    push es
    mov es,[es:2ch] ;сегмент окружения из PSP
    mov ah,49h  ;функция освобождения блока памяти
    int 21h     ;освободить сегмент окружения
    pop es      ;es указывет на начало программы в памяти
    mov ah,49h  ;функция освобождения блока памяти
    int 21h     ;выгрузить программу
    push cs
    pop ds      ;ds=cs
    mov dx,un   ;адрес строки
    mov ah,09h  ;функция вывода строки на экран
    int 21h     ;выводим на экран
    jmp ex
isunload:   ;проверка ключа выгрузки
    mov si,81h      ;начало командной строки
l1:     mov al,[si]     ;взять очередной символ
    cmp al,13       ;если конец командной строки
    jz no           ;то нет ключа выгрузки
    cmp al,' '      ;если не пробел
    jnz l2          ;то есть параметр командной строки
    inc si          ;следующий символ
    jmp l1          ;продолжить поиск
l2: cmp [si],byte '/'   ;если первый символ ключа не /
    jnz no          ;то нет ключа выгрузки
    cmp [si+1],byte 'U' ;если первый /
    jz yes          ;и второй U или u
    cmp [si+1],byte 'u'
    jz yes          ;то есть ключ
no: mov al,0        ;нет ключа
    ret
yes:    mov al,1        ;есть ключ
    ret
Success     db  10,13,'Program loaded',10,13,'$'
already     db  10,13,'Already loaded',10,13,'$'
un      db  10,13,'Program unloaded',10,13,'$'

Объяснение кода листинга программы

  1. Резидентная программа написана на ассемблере.
  2. Программа использует 16-битный режим.
  3. Смещение программы в памяти 100h.
  4. В начале программы есть инструкция jmp InstallTSR, которая загружает программу в память.
  5. В Old08h хранится резервированный адрес оригинального обработчика прерывания 08h.
  6. В счетчике cnt хранится количество итераций, которые должны быть выполнены.
  7. Переменная col используется для хранения текущего цвета фона.
  8. Новый обработчик прерывания int08h находится в New08Obrab.
  9. Если счетчик cnt не равен 0, то выполняется цикл m1, который изменяет цвет фона.
  10. Если цвет фона не равен 0, то выполняется цикл m2, который изменяет цвет символов на экране.
  11. В начале каждой строки видеопамяти находится адрес начального символа в верхнем левом углу.
  12. Адрес обработчика прерывания 08h сохраняется в регистрах BX и ES.
  13. Если ключ выгрузки не найден, то выводится сообщение Program loaded.
  14. Если ключ выгрузки найден, то выводится сообщение Program unloaded.

ИИ поможет Вам:


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

Оцени полезность:

8   голосов , оценка 3.875 из 5