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

Offline tysonprogrammer

  • Jr. Member
  • *
  • Posts: 22
  • 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: 2667
  • 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: 373
  • 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: 22
  • 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

Offline Sharlenehargrove

  • Jr. Member
  • *
  • Posts: 7
Re: Converting DOS TSR example from MASM to NASM
« Reply #4 on: January 20, 2023, 05:05:30 AM »
I just want to say that when converting an example DOS TSR (Terminate and Stay Resident) program written in MASM (Microsoft Macro Assembler) to NASM (Netwide Assembler), one of the main things you'll need to change is how the program calls the old interrupt.

In MASM, you would use the INT instruction to call the interrupt, followed by the interrupt number in hexadecimal. For example, to call interrupt 21h (the DOS interrupt), you would use the instruction INT 21h.

In NASM, you would use the int instruction, followed by the interrupt number in decimal. To call interrupt 21 (the DOS interrupt), you would use the instruction int 21. Dinar Guru
« Last Edit: January 23, 2023, 03:52:09 AM by Sharlenehargrove »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Converting DOS TSR example from MASM to NASM
« Reply #5 on: January 20, 2023, 05:14:03 AM »
That does NOT sound correct to me!

Best,
Frank


Offline fredericopissarra

  • Full Member
  • **
  • Posts: 373
  • Country: br
Re: Converting DOS TSR example from MASM to NASM
« Reply #6 on: January 20, 2023, 11:01:15 AM »
In NASM, you would use the int instruction, followed by the interrupt number in decimal. To call interrupt 21 (the DOS interrupt), you would use the instruction int 21.

Nope... int 21h works the same way, but I prefer writing hexadecimal in C style: int 0x21

See NASM documentation: here