How to pass/retrieve DOS command-line parameters in a 16-bit assembly program?
Asked Answered
R

2

7

I am writing some little tools for MS-DOS. Now I'm writing a Shutdown.com, like for Windows XP and greater. I have already written the entire code, now I just need to pass the argument from DOS.

I need to pass the parameters "-r" to reboot and "-s" to shutdown.

How can I do it?

I'm using TASM(Turbo Assembler 4.1) on Windows 98 to link and compile. I'm looking for a very simple way to do it, and if possible, still a .COM program. I'm looking exactly like the ARGV and ARGC from C language, but for Assembly 16-bits...

  • shutdown -r will reboot
  • shutdown -s will shutdown

Remember that I already know how to reboot and how to shutdown the PC.
I just need to learn how to pass the parameters from the MS-DOS command line to my program.

Rancher answered 3/1, 2017 at 17:11 Comment(9)
What entity are you calling? Another program? BIOS? How does the assembly program expect the parameters to be passed?Organism
I'm on MS-DOS shell, calling the shutdown.com. Like I call others programs like MOVE, FORMAT, FDISK.Rancher
Is shutdown.com a command line program? That is, to use it from the command line, can you type shutdown -r?Organism
Yes, it's a command line command. Well, My program isn't waiting parameters because I don't know how to pass them hehehe. What is the simpliest way to do it? So, I will implement my code.Rancher
I need to make my program prepare to receive parameters from MS-DOS command lineRancher
.com files receive parameters in the PSP at offset 80h. That page even has assembly sample code ;)Pennant
As a point of interest, does your shutdown.com work? I thought XP and above wouldn't allow 16-bit applications to shut down the machine.Locoism
Of course they don't, @klitos. He's not using Windows, he's actually writing a DOS application. You know, one that runs in DOS, not NT DOS.Carrolcarroll
@KlitosKyriacou Here the code from my shutdown. Works on MS-DOS, but not in Windows 98. Works perfectly here.Rancher
C
11

There is no specific API to retrieve the command-line in MS-DOS. Instead, you have to read the value from the appropriate offset of the Program Segment Prefix (PSP), which is a data structure that DOS uses to store program-specific data.

At offset 80h, there is a 1-byte value that gives the length of the command-line arguments. The actual command-line argument string starts at offset 81h, and can be up to 127 bytes in length. You know how long it is based on the value at offset 80h, but it will also be terminated with a carriage return (0Dh).

You can use these offsets relative to the pointer in the DS register when the program is first executed. Otherwise, you call INT 21h with AH set to 62h to retrieve a pointer to the current PSP in the BX register. (Function 62h requires DOS 3 or later; on DOS 2, you can use the undocumented function 51h).

The old, 16-bit DOS version of Randall Hyde's Art of Assembly is available for free online (in HTML and PDF formats). In Chapter 13, section 13.3.11 describes the PSP, and the following two sections (13.3.12–13) explain how to access and parse command-line parameters, including sample code.

Carrolcarroll answered 3/1, 2017 at 17:30 Comment(1)
Worth mentioning that the first byte (at 81h) will apparently be space or '/', not what you'd expect in argv[1][0] in a C main(), or a POSIX argv.Hazlitt
F
7

According to this site, the length of the command-line is stored at DS:80h (single byte), and the actual command line itself starts at DS:81h. Here's some example code from that article that prints the command line:

; ----------------------------------------------------------------------------
; echo.asm
;
; Echoes the command line to standard output.  Illustrates DOS system calls
; 40h = write to file, and 4ch = exit process.
;
; Processor: 386 or later
; Assembler: MASM
; OS: DOS 2.0 or later only
; Assemble and link with "ml echo.asm"
; ----------------------------------------------------------------------------

        .model  small
        .stack  64                      ; 64 byte stack
        .386
        .code
start:  movzx   cx,byte ptr ds:[80h]    ; size of parameter string
        mov     ah, 40h                 ; write
        mov     bx, 1                   ; ... to standard output
        mov     dx, 81h                 ; ... the parameter string
        int     21h                     ; ... by calling DOS
        mov     ah, 4ch
        int     21h
        end     start             
Fructiferous answered 3/1, 2017 at 17:24 Comment(4)
I'm having a trouble when I try to compare the ASCII char on dx. How can I compare the char?Rancher
@Rancher - you could first scan for the '-', either in a loop or using repne scasb (cx = count, di = address), then check if the next character is 'r' or 'R' or 's' or 'S' (you could or 020h and check for 'r' or 's').Fujimoto
How can I do that? I tried an little experiment here but id doesn't work.Rancher
.model small .stack 64 .386 .code start: movzx cx,byte ptr ds:[80h] mov ah, 40h mov bx, 1 mov dx, 81h cmp dl,'A' jnz sair int 21h sair: mov ah, 4ch int 21h end start This only print if the enter was 'A', but won't works.Rancher

© 2022 - 2024 — McMap. All rights reserved.