flat assembler
Message board for the users of flat assembler.
![]() |
Author |
|
revolution 20 Mar 2025, 03:35
Opcode 0xea is a direct jump.
You need an indirect jump: Code: somewhere: dw 0x1234,0x5678 ;... jmp far [somewhere] Last edited by revolution on 20 Mar 2025, 03:36; edited 1 time in total |
|||
![]() |
|
macomics 20 Mar 2025, 03:36
That's how it's supposed to work. But it still need to provide at least 8KB of free memory to run. (see ah=4a/int 21h)
Code: org 100h ; .COM file format (simpler for TSR) jmp install_tsr ; Data Section dos_terminate equ 4Ch ; DOS function to terminate program command_com db "\COMMAND.COM",0 batch_filename db 7,"\TM.BAT" ; Batch file to execute null_string db 0 execParamBlock: .envOffset dw 0 .envSegment dw 0 .argOffset dw batch_filename .argSegment dw 0 .inputHandle dw 0 .inputSegment dw 0 .outputHandle dw 0 .outputSegment dw 0 old_int21 dd ? ; Placeholder for old INT 21h handler old_stack dd ? ; Hooked INT 21h handler int21_hook: cmp ah, dos_terminate ; Check if function 4Ch is called jne next_handler ; Call batch file before terminating pushad push ds push es mov word [cs:old_stack], sp mov word [cs:old_stack+2], ss mov [execParamBlock.envSegment], cs ; PSP mov [execParamBlock.argSegment], cs ; CS:batch_filename mov [execParamBlock.inputSegment], cs mov [execParamBlock.outputSegment], cs push cs pop ds push cs pop es mov bx, execParamBlock mov dx, command_com mov ah, 4Bh ; Execute program mov al, 0 ; Load and execute int 21h ; Call DOS lss sp, [cs:ols_stack] pop es pop ds popad next_handler: jmp far [cs:old_int21] ; Call original INT 21h ; Installation routine install_tsr: cli mov ax, 3521h ; Get old INT 21h handler int 21h mov word [old_int21], bx mov word [old_int21+2], es ; Store old handler push cs pop ds mov dx, int21_hook mov ax, 2521h ; Set new INT 21h handler int 21h sti ; Stay resident (allocate memory for TSR) mov dx, (end_program - install_tsr + 15) / 16 ; Calculate memory in paragraphs mov ah, 31h ; DOS stay-resident function int 21h end_program: |
|||
![]() |
|
Core i7 20 Mar 2025, 04:02
ax=3521h corrupts ES, so it needs to be preserved
|
|||
![]() |
|
macomics 20 Mar 2025, 04:10
ver 2.0
Code: org 100h ; .COM file format (simpler for TSR) jmp install_tsr ; Data Section dos_terminate equ 4Ch ; DOS function to terminate program command_com db "\COMMAND.COM",0 batch_filename db 10,"/C \TM.BAT" ; Batch file to execute null_string db 0 execParamBlock: .envSegment dw 0 .argOffset dw batch_filename .argSegment dw 0 .inputHandle dw fcb0 .inputSegment dw 0 .outputHandle dw fcb1 .outputSegment dw 0 fcb0: .drive db 2 .file_name db ' ', ' ' .block db 20 dup (0) .rec_curr db 0 .rec_numb db 0,0,0 fcb1: .drive db 2 .file_name db ' ', ' ' .block db 20 dup (0) .rec_curr db 0 .rec_numb db 0,0,0 old_int21 dd ? ; Placeholder for old INT 21h handler old_stack dd ? old_mysssp dd ? ; Hooked INT 21h handler int21_hook: cmp ah, dos_terminate ; Check if function 4Ch is called jne next_handler ; Call batch file before terminating mov word [cs:old_stack], sp ; Save stack pointer of the current program mov word [cs:old_stack+2], ss mov word [cs:old_mysssp], stack_area + 254 ; Switching to the stack block for this resident mov word [cs:old_mysssp+2],cs lss sp, [cs:old_mysssp] pushad ; Save all general-purpose registers for the current program push ds ; and data segment registers push es mov ax, 2521h ; Remove the hook so that the program does not call us before exiting. lds dx, [old_int21] int 21h push cs ; Truncating the memory of this resident so that there is a place to load the new program. pop es mov bx, (end_program - 8177) / 16 mov ah, 4Ah int 21h push cs ; Run program pop ds push cs pop es mov word [cs:old_mysssp], sp mov word [cs:old_mysssp+2], ss mov [execParamBlock.envSegment], cs ; PSP mov [execParamBlock.argSegment], cs ; CS:batch_filename mov [execParamBlock.inputSegment], cs mov [execParamBlock.outputSegment], cs mov bx, execParamBlock mov dx, command_com mov ah, 4Bh ; Execute program mov al, 0 ; Load and execute int 21h ; Call DOS lss sp, [cs:old_mysssp] ; Restoring the stack pointer value before calling the program call set_hook ; Restoring the hook push cs ; Restoring a memory block pop es mov bx, (end_program + 15) / 16 mov ah, 4Ah int 21h pop es ; Restoring registers to the pre-interrupt state pop ds popad lss sp, [cs:ols_stack] next_handler: jmp far [cs:old_int21] ; Call original INT 21h set_hook: push cs pop ds mov dx, int21_hook mov ax, 2521h ; Set new INT 21h handler int 21h retn ; Installation routine install_tsr: cli mov ax, 3521h ; Get old INT 21h handler int 21h mov word [old_int21], bx mov word [old_int21+2], es ; Store old handler call set_hook sti ; Stay resident (allocate memory for TSR) mov dx, (end_program - install_tsr + 15) / 16 ; Calculate memory in paragraphs mov ah, 31h ; DOS stay-resident function int 21h stack_area rb 256 free_block rb 8192 end_program: |
|||
![]() |
|
OgreVorbis 21 Mar 2025, 05:35
Thanks for the help, but neither of those work.
First, I had to correct the line "lss sp, [cs:ols_stack]". It says "ols" instead of "old". Easy fix and now the program compiles. Geat! After fixing the typo, the first program doesn't work though. The TSR does seem to install itself correctly, but what ends up happening is that whenever any program terminates, it just starts beeping the PC speaker constantly and locks up the OS. So it's not working correctly, but it does seem to install the TSR and run at the appropriate time. The second version won't compile even after fixing the typo of "ols" to "old". It has a synatx error on line 21. It says there are trailing characters after "db 20 dup (0)". However, to me it seems there is nothing wrong, so I suspect maybe there is a problem with the version of FASM I am running. I think it's version 1.6 if I remember correctly. I'll try to update my FASM to see if that fixes it. =========================================================================================== I am not sure why you need command.com written in there. Can't it just run the batch file, or does it have to run it in a new instance of command.com? Just to be more clear. The TM.BAT is located in C:\DOS and is part of the PATH, hence why I don't write a path for it. |
|||
![]() |
|
OgreVorbis 21 Mar 2025, 06:07
OK, so I did find out that the reason V2.0 wasn't compiling was because of an old version of FASM V1.6.
So I updated and the program compiled successfully. But, well, it doesn't work though. It no longer crashes the PC when exiting other programs, but it just doesn't do anything. A few minutes later the PC just locked up though, so... I have a feeling this is one of those problems that will never be solved properly. It's going way over my head. I can't believe DOS has this annoying problem. In windows, when you terminate a program which uses a different screen resolution than the OS, it will change the resolution back. |
|||
![]() |
|
macomics 21 Mar 2025, 07:56
OgreVorbis wrote: After fixing the typo, the first program doesn't work though. The TSR does seem to install itself correctly, but what ends up happening is that whenever any program terminates, it just starts beeping the PC speaker constantly and locks up the OS. So it's not working correctly, but it does seem to install the TSR and run at the appropriate time. Code: org 100h ; .COM file format (simpler for TSR) jmp install_tsr struc EPB { ; EXEC parameters block .envSegment dw 0 .argOffset dw 0 .argSegment dw 0 .inputHandle dw 0 .inputSegment dw 0 .outputHandle dw 0 .outputSegment dw 0 } struc FCB { ; File control block .drive db 2 .file_name db ' ', ' ' .block db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .rec_curr db 0 .rec_numb db 0,0,0 } ; Data Section dos_terminate equ 4Ch ; DOS function to terminate program command_com db "\COMMAND.COM",0 batch_filename db 10,"/C \TM.BAT" ; Batch file to execute null_string db 0 execParamBlock EPB fcb0 FCB fcb1 FCB old_int21 dd ? ; Placeholder for old INT 21h handler old_stack dd ? old_mysssp dd ? ; Hooked INT 21h handler int21_hook: cmp ah, dos_terminate ; Check if function 4Ch is called jne next_handler ; Call batch file before terminating mov word [cs:old_stack], sp ; Save stack pointer of the current program mov word [cs:old_stack+2], ss mov word [cs:old_mysssp], stack_area + 254 ; Switching to the stack block for this resident mov word [cs:old_mysssp+2],cs lss sp, [cs:old_mysssp] pushad ; Save all general-purpose registers for the current program push ds ; and data segment registers push es mov ax, 2521h ; Remove the hook so that the program does not call us before exiting. lds dx, [cs:old_int21] int 21h push cs ; Truncating the memory of this resident so that there is a place to load the new program. pop es mov bx, (end_program - 8177) / 16 mov ah, 4Ah int 21h push cs ; Run program pop ds push cs pop es mov word [old_mysssp], sp mov word [old_mysssp+2], ss mov [execParamBlock.envSegment], cs ; PSP mov [execParamBlock.argOffset], batch_filename mov [execParamBlock.argSegment], cs ; CS:batch_filename mov [execParamBlock.inputHandle], fcb0 mov [execParamBlock.inputSegment], cs mov [execParamBlock.outputHandle], fcb1 mov [execParamBlock.outputSegment], cs mov bx, execParamBlock mov dx, command_com mov ax, 4B00h ; Execute program (Load and execute) int 21h ; Call DOS push cs pop ds lss sp, [old_mysssp] ; Restoring the stack pointer value before calling the program call set_hook ; Restoring the hook push cs ; Restoring a memory block pop es mov bx, (end_program + 15) / 16 mov ah, 4Ah int 21h pop es ; Restoring registers to the pre-interrupt state pop ds popad lss sp, [cs:old_stack] next_handler: jmp far [cs:old_int21] ; Call original INT 21h set_hook: mov dx, int21_hook mov ax, 2521h ; Set new INT 21h handler int 21h retn ; Installation routine install_tsr: cli mov ax, 3521h ; Get old INT 21h handler int 21h mov word [old_int21], bx mov word [old_int21+2], es ; Store old handler call set_hook sti ; Stay resident (allocate memory for TSR) mov dx, (end_program - install_tsr + 15) / 16 ; Calculate memory in paragraphs mov ah, 31h ; DOS stay-resident function int 21h stack_area rb 256 free_block rb 8192 end_program: But in general, I have shown you how the program should be built. 1) Before starting a new program, it is necessary to restore the hook because the new program will also end and there will be a repeated (endless) launch upon completion. 2) MS DOS allocates all available memory for a single running program. Even before termination, all the memory is still occupied. To load another program into memory, you need to find a free memory block. Such a block is kept by a resident. He releases it for the duration of the program launch and takes it back after its completion. 3) You cannot run BAT files via EXEC. It is necessary to call the executable program. In this case, it is COMMAND.COM which, as I assume in my program, should be located at the root of the current drive. If the current drive is D: and there is no COMMAND.COM , then the BAT file will not start. 4) All registers must be saved before starting. Although it's not particularly important. But I did it out of habit. And I keep all the 32-bit general purpose registers. 5) To run a program, you may need more stack space than the current program has. So I switch to my stack memory block for work. That's where all the registers are saved. ADD: There is also an int 20h interrupt to terminate the program. It also needs to be intercepted and processed in a similar way. |
|||
![]() |
|
macomics 21 Mar 2025, 08:19
One more thing. It is better not to use int 21h, but to call directly
Code: ; instead every int 21h pushf call far [cs:old_int21h] |
|||
![]() |
|
Core i7 21 Mar 2025, 09:58
OgreVorbis wrote: I have a feeling this is one of those problems that will never be solved properly. It's going way over my head. I can't believe DOS has this annoying problem. you need to write a bootloader to run the games. Such programs in DOS are known as "semi-resident". In your bootloader, you free all the memory after yourself AH=4Ah, where you then load the game AX=4B01h, and launch it via JMP. When the game is over, it returns control back to your bootloader. For your case, this is better than resident. |
|||
![]() |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.