NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: tysonprogrammer 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
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
; 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
-
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:
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
-
Another thing:
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:
jmp far [cs:old_interrupt9]
Yet another thing: This
and ah,!ctrl_key
Won'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:
and ah,~ctrl_key
Here's your code with some corrections and comments of mine:
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
-
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
-
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 (https://www.dinarguru.onl/)
-
That does NOT sound correct to me!
Best,
Frank
-
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 (https://www.nasm.us/doc/nasmdoc3.html#section-3.4.1)