Author Topic: Converting DOS TSR example from MASM to NASM  (Read 291 times)

Offline tysonprogrammer

  • Jr. Member
  • *
  • Posts: 15
  • Country: us
  • C# application developer attempting assembly.
Converting DOS TSR example from MASM to NASM
« on: September 06, 2022, 09:54:01 PM »
Hello,

I am trying to convert an example DOS TSR from MASM to NASM. I think I have most of it. Only thing I am not sure about is the part calling the old interrupt

Here is the original MASM version

Code: [Select]
TITLE Reset-Disabling program                  (No_Reset.asm)

; This program disables the usual DOS reset command
; (Ctrl-Alt-Del), by intercepting the INT 9 keyboard
; hardware interrupt.  It checks the shift status bits
; in the MS-DOS keyboard flag and changes any Ctrl-Alt-Del
; to Alt-Del.  The computer can only be rebooted by
; typing Ctrl+Alt+Right shift+Del.  Assemble, link,
; and convert to a COM program by including the /T
; command on the Microsoft LINK command line.
; Last update: 12/12/2004

.model tiny
.386
.code
rt_shift   EQU 01h ; Right shift key: bit 0
ctrl_key   EQU 04h ; CTRL key: bit 2
alt_key    EQU 08h ; ALT key: bit 3
del_key    EQU 53h ; scan code for DEL key
kybd_port  EQU 60h ; keyboard input port

ORG   100h        ; this is a COM program
start:
jmp   setup      ; jump to TSR installation

;   Memory-resident code begins here
int9_handler PROC FAR
sti                ; enable hardware interrupts
pushf ; save regs & flags
push  es
push  ax
push  di

;   Point ES:DI to the DOS keyboard flag byte:
L1: mov   ax,40h              ; DOS data segment is at 40h
mov   es,ax
mov   di,17h              ; location of keyboard flag
mov   ah,es:[di]          ; copy keyboard flag into AH

;   Test for the CTRL and ALT keys:
L2: test  ah,ctrl_key        ; CTRL key held down?
jz    L5                  ; no: exit
test  ah,alt_key          ; ALT key held down?
jz    L5                  ; no: exit

;   Test for the DEL and Right-shift keys:
L3: in    al,kybd_port        ; read keyboard port
cmp   al,del_key          ; DEL key pressed?
jne   L5                  ; no: exit
test  ah,rt_shift        ; right shift key pressed?
jnz   L5                  ; yes: allow system reset

L4: and   ah,NOT ctrl_key    ; no: turn off bit for CTRL
mov   es:[di],ah          ; store keyboard_flag

L5: pop   di                  ; restore regs & flags
pop   ax
pop   es
popf
; here is the code I am not sure about
jmp   cs:[old_interrupt9] ; jump to INT 9 routine

old_interrupt9 DWORD ?

int9_handler ENDP
end_ISR label BYTE

; --------------- (end of TSR program) ------------------
;   Save a copy of the original INT 9 vector, and set up
;   the address of our program as the new vector.  Terminate
;   this program and leave the int9_handler procedure in memory.

setup:
mov ax,3509h            ; get INT 9 vector
int 21h
mov word ptr old_interrupt9,bx ; save INT 9 vector
mov word ptr old_interrupt9+2,es

mov ax,2509h            ; set interrupt vector, INT 9
mov dx,offset int9_handler
int 21h

mov ax,3100h ; terminate and stay resident
mov dx,OFFSET end_ISR  ; point to end of resident code
shr dx,4 ; divide by 16
inc dx ; round upward to next paragraph
int 21h                ; execute MS-DOS function
END start

Here is my NASM port
Code: [Select]
; TITLE Reset-Disabling Program
section code
%define syscall int 0x21

rt_shift            EQU 0x01
ctrl_key            EQU 0x04
alt_key             EQU 0x08
del_key             EQU 0x53
keybd_port          EQU 0x60

org 0x100
start:
    jmp setup

; memory resident code starts here
int9_handler:
    sti                                         ; enable hardwrae interrupts
    ; save registers and CPU flags
    pushf                       
    push es
    push ax
    push di
; Point ES_DI to the DOS keyboard flag byte
L1:
    mov ax, 0x40                                ; DOS data segment is at 0x40
    mov es, ax                                  ; set es to the data segment
    mov di, 0x17                                ; location of keyboard flag
    mov ah, [es:di]                             ; copy the keyboard flag to ah
; Test for the CTRL and ALT keys
L2:
    test ah, ctrl_key                           ; is CTRL key down?
    jz L5                                       ; no: exit
    test ah, alt_key                            ; is ALT key down
    jz L5                                       ; no: exit
; Test for DEL and Right Shift keys
L3:
    in al, keybd_port
    cmp al, del_key                             ; is DEL key down?
    jz L5                                       ; no: exit
    test ah, rt_shift                           ; is Right shft down
    jnz L5                                      ; no: exit
L4:
    and ah,!ctrl_key                            ; no turn off bit for ctrl 
    mov [es:di], ah                             ; store keyboard flag
L5:
    pop di
    pop ax
    pop es
    popf
-- here is my version
    jmp [cs:old_interrupt9]
old_interrupt9: dd 0x00000000
end_ISR:        db 0

; ------ end of TSR program -------
; Save a copy of the original interrupt vector and set up
; the address of our program as the new vector, Terminate
; this program and save the int9_handler procedure in memory.
setup:
    mov ax, 0x3509                              ; get int9 vector
    syscall

    mov word [old_interrupt9], bx               ; Save old interrupt vector
    mov word [old_interrupt9+2], es             ; Save old interrupt segment
    mov ax, 0x2509                              ; set interrupt vector
    mov dx, int9_handler
    syscall
   
    mov ax, 0x3100                              ; terminate and stay resident
    mov dx, end_ISR                             ; set end of ISR
    shr dx, 4                                   ; divide by 16
    inc dx                                      ; move upword to next paragraph
    syscall                                     ; excute DOS function

What I not sure about is jmp cs:[old_interrupt9]

Any help would be appreciated.

Tyson

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2597
  • Country: us
Re: Converting DOS TSR example from MASM to NASM
« Reply #1 on: September 06, 2022, 10:54:25 PM »
Hi Tyson,

There are "known" section names. ".text" (lower case!) is one, "code" is not. I don't think ut makes any difference in this case, but...

I think Nasm likes everything inside the brackets:
Code: [Select]
call [cs: old_interrupt9]
cs" on the previous line might also work.

Sorry we didn't have that other TSR you were looking for.

Best,
Frank


Offline fredericopissarra

  • Full Member
  • **
  • Posts: 228
  • Country: br
Re: Converting DOS TSR example from MASM to NASM
« Reply #2 on: September 07, 2022, 01:09:42 PM »
Another thing:
Code: [Select]
jmp [cs:old_interrupt9]Is an NEAR absolute indirect jump (uses the same CS and takes the offset from the address). What you need is a FAR absolute indirect jump (takes CS and the offset from the address). The correct instruction should be:
Code: [Select]
jmp far [cs:old_interrupt9]
Yet another thing: This
Code: [Select]
and ah,!ctrl_keyWon't do what you thing it does... ! operador is a BOOLEAN operator (as in C) and results in 0 or 1, always. What you are searching for is ~ (BINARY NOT operator). The correct instruction is:
Code: [Select]
and ah,~ctrl_keyHere's your code with some corrections and comments of mine:
Code: [Select]
  bits  16

  org   0x100

; Notice: NO segments needed!

; This program disables the usual DOS reset command
; (Ctrl-Alt-Del), by intercepting the INT 9 keyboard
; hardware interrupt.  It checks the shift status bits
; in the MS-DOS keyboard flag and changes any Ctrl-Alt-Del
; to Alt-Del.  The computer can only be rebooted by
; typing Ctrl+Alt+Right shift+Del.
;
; Use NASM -fbin prog.asm -o prog.com

RT_SHIFT   EQU 0x01     ; Right shift key: bit 0
CTRL_KEY   EQU 0x04     ; CTRL key: bit 2
ALT_KEY    EQU 0x08     ; ALT key: bit 3
DEL_KEY    EQU 0x53     ; scan code for DEL key
KEYB_PORT  EQU 0x60     ; keyboard input port

  jmp   setup           ; jump to TSR installation

;   Memory-resident code begins here
int9_handler:
  sti                   ; enable hardware interrupts
  pushf                 ; save regs & flags
  push  ds              ; Using DS instead of ES to avoid prefixes
  push  ax
  push  bx              ; Using BX as base address (not DI), just to
                        ; be compliant to 8086 effective addresses standard.

  ; Point DS:BX to the BIOS data area keyboard flag (0x40:0x17) byte
  mov   ax,0x40
  mov   ds,ax
  mov   bx,0x17

  mov   ah,[bx]               ; copy keyboard flag into AH

  ; Test for the CTRL and ALT keys:
  test  ah,CTRL_KEY           ; CTRL key held down?
  jz    .exit                 ; no: exit
  test  ah,ALT_KEY            ; ALT key held down?
  jz    .exit                 ; no: exit

  ; Test for the DEL and Right-shift keys:
  in    al,KEYB_PORT          ; read keyboard port
  cmp   al,DEL_KEY            ; DEL key pressed?
  jne   .exit                 ; no: exit
  test  ah,RT_SHIFT           ; right shift key pressed?
  jnz   .exit                 ; yes: allow system reset

  ; FIXED: !CTRL_KEY will result in 0, not 0xFB. ! is a BOOLEAN NOT operator. ~ is a BINARY NOT.
  and   ah,~CTRL_KEY          ; no: turn off bit for CTRL
  mov   [bx],ah               ; store modified keyboard_flag

.exit:
  pop   bx                    ; restore regs & flags
  pop   ax
  pop   ds
  popf

  ; FIXED: Must be a far jump!
  jmp   far [cs:old_interrupt9]   ; jump to INT 9 routine

old_interrupt9:
  align 2
  dd    0
service_end:

; --------------- (end of TSR program) ------------------
;   Save a copy of the original INT 9 vector, and set up
;   the address of our program as the new vector.  Terminate
;   this program and leave the int9_handler procedure in memory.

setup:
  cli                       ; Disable interrupts to NOT allow
                            ; IVT changes when we are tring to
                            ; change it.

  mov ax,0x3509             ; get old INT 9 vector
  int 0x21
  mov [old_interrupt9],bx
  mov [old_interrupt9+2],es

  ; In tiny model DS=CS.
  mov ax,0x2509             ; set new int 9 vector
  mov dx,int9_handler
  int 0x21

  ; Calculate # of paragraphs...
  mov dx,service_end        ; point to end of resident code
                            ; this works only because the initial offset is
                            ; always zero.
  mov ah,dl
  mov cl,4
  shr dx,cl                 ; OBS: shr dx,4 ISN'T an 8086 instruction!
  test ah,0x0f              ; Any bytes remaining in the last paragraph?
  jz  .skip                 ; No, ok...
  inc dx                    ; Yes. Add an extra paragraph
.skip:

  mov ax,0x3100             ; terminate and stay resident
  int 0x21
« Last Edit: September 07, 2022, 02:09:39 PM by fredericopissarra »

Offline tysonprogrammer

  • Jr. Member
  • *
  • Posts: 15
  • Country: us
  • C# application developer attempting assembly.
Re: Converting DOS TSR example from MASM to NASM
« Reply #3 on: September 07, 2022, 11:20:18 PM »
thanks Fred, it now builds and runs without causing a crash.  Once I get it cleaned up I will post for others to enjoy.

Tyson