Справка Написание программы TSR ( s) в сборке NASM для DOS

Я пытался писать программы TSR (Terminate-Stay-Resident) (в общем) на Assembly (16- bit) для MS-DOS. Я прочитал страницу в Википедии на TSR, а также страницу, посвященную его использованию специально в DOS (но, похоже, он обучает его на C, а не непосредственно на ассемблере). Я просмотрел сайт с тоннами документации по прерываниям DOS и нашел этот , этот и еще один, наиболее подходящий для программ TSR. Я не могу опубликовать все ссылки, потому что как новый пользователь я могу иметь до 2 гиперссылок в сообщении.

Итак, я попытался написать (казалось бы) очень простую программу TSR в плоской модели реального режима (. Формат файла COM) в NASM. Вот код:

[BITS 16]
[ORG 0x0100]

[SECTION .text]

Start:
; Get current interrupt handler for INT 21h
mov AX,3521h                ; DOS function 35h GET INTERRUPT VECTOR for interrupt 21h
int 21h                     ; Call DOS  (Current interrupt handler returned in ES:BX)

mov WORD [v21HandlerSegment],ES     ; Store the current INT 21h handler segment
mov WORD [v21HandlerOffset],BX      ; Store the current INT 21h handler offset

; Write new interrupt handler for INT 21h
mov AX,2521h                ; DOS function 25h SET INTERRUPT VECTOR for interrupt 21h
mov DX,TSRStart             ; Load DX with the offset address of the start of this TSR program
;   DS already contains the segment address, it is the same as CS in this .COM file
int 21h                     ; Override the INT 21h handler with this TSR program

; The TSR program will be called even when this portion uses INT 21h to terminate and stay resident
mov AX,3100h                ; DOS function TSR, return code 00h
mov DX,00FFh                ; I don't know how many paragraphs to keep resident, so keep a bunch
int 21h                     ; Call our own TSR program first, then call DOS

TSRStart:
push WORD [v21HandlerSegment]       ; Push the far address of the original 
push WORD [v21HandlerOffset]        ;   INT 21h handler onto the stack
retf                                ; Jump to it!


[SECTION .data]
v21HandlerSegment dw 0000h
v21HandlerOffset  dw 0000h

Когда я собираю это и выполняю внутри DOS, вместо возврата к приглашению DOS система зависает (никаких действий не происходит, за исключением того, что аппаратный курсор просто мигает под последней подсказкой). Я предполагаю, что мусор памяти может выполняться, но вы уловили суть.

Может ли кто-нибудь помочь выяснить, в чем проблема с этим кодом, и / или дать общий совет по кодированию TSR в DOS? Заранее благодарим за любую помощь!

9
задан Alex Ozer 27 July 2011 в 17:32
поделиться

1 ответ

  1. необходимо использовать cs: переопределение сегмента для доступа к данным TSR из обработчика прерываний общего назначения, потому что эти ds значение является регистром произвольного пользователя затем.

  2. Вы не должны продвигать адрес следующего обработчика на стек, затем переходят с retf. Более просто сделать jmp far [cs:...] (и это имеет более короткое кодирование). Но Ваш метод хорошо работает также.

  3. можно поместить обработку инициализации (не нужный в установленном обработчике резидентного объекта) в конце изображения программы. Это - тривиальная оптимизация размера TSR.

  4. Для вычисления размера резидентного процесса используйте маркировки NASM. Чтобы позволить сдвиг (или разделиться), операции должны были выяснить длину в абзацах, только использовать дельты маркировок. Дельта (различие) является скалярной величиной к NASM, так может использоваться в вычислениях. Одна только (non-struc) маркировка не является скаляром.

Вот пример с помощью всех них:

        cpu 8086
        bits 16
        org 256

start:
        jmp init

        align 4
int21old:
        dd 0

int21handler:
        jmp far [cs:int21old]

end_of_resident:

init:
        mov ax, 3521h
        int 21h
        mov word [int21old + 2], es
        mov word [int21old], bx

        mov ax, 2521h
        mov dx, int21handler
        int 21h

        mov ax, 3100h
        mov dx, (end_of_resident - start + 256 + 15) >> 4
        int 21h

вычисление размера вычисляет дельту двух маркировок, добавляет в 256 для PSP процесса (то же как org 256), добавляет 15, чтобы заставить shift-division окружить, затем смещается вниз в сумму абзацев.

1
ответ дан 3 November 2019 в 04:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: