On Tue, 12 Jul 2022, C. Masloch wrote:
(Only replied-to portions copied)
Further, you calculate the size of the PSP block to keep resident by using
test, add, and shifts:
mov dx, trans ; Allow everything preceding the
test dx, 0x000F ; transient portion of GRAFTABL to
jz .20 ; remain resident. (Rounded up to
add dx, 0x10 ; the next paragraph, because
MS-DOS
.20: mov cl, 4 ; wants the size in paragraphs.)
shr dx, cl
mov ax, 0x3100
int 0x21 ; TSR EXIT CODE 0
It is more efficient to change this like so:
mov dx, trans
add dx, 15
mov cl, 4
shr dx, cl
The "add dx, 15" makes the shr round up in its division. (I expect that the
addition won't overflow here.) However, you can easily change it so that the
addition is done by the assembler at build time, using "mov dx, trans + 15".
Prolly the 65C02 programmer in me. xD
Another problem (which is also little known) is that your use of interrupt
21h service 31h will retain all of your currently open process handles, as
well as the entire system's System File Table (SFT) entries associated with
these. This is not a problem by default because all your handles will be
DUPlicated from the parent's, for your stdin, stdout, stderr, stdaux, and
stdprn. That means they will share the same SFT entries as already used by
the shell. However, if the user runs your program with output redirection
(either to a file or a character device such as NUL), as in "graftabl > nul",
then you will leak the SFT entry which was reserved for your process to use.
I assume that the people involved in the design of this DOS service expected
that TSRs would generally want to keep around their PSPs, so that they could
swap processes and then use their own handles as preserved in their process
handle tables. However, in practice most TSRs never re-use their PSPs after
the DOS TSR termination handling is done. So in that case, as it is for your
application, you should explicitly free all handles before terminating.
Here's how I solved it [7] in FDAPM (and with equivalent code in FreeDOS
SHARE):
xor bx, bx ; = 0
mov cx, word [32h] ; get amount of handles
.loop:
mov ah, 3Eh
int 21h ; close it
inc bx ; next handle
loop .loop ; loop for all process handles -->
Hm. Probably a good point.
In your executable entrypoint you have a near jump to skip the buffer later
used for the table data:
entry: jmp trans
db 1021 dup 0x00
It is implied by the size of the buffer that the jump must be near, so it
takes 3 bytes, and then you add another 1021 bytes to get a total of 1024
bytes. (I think the "dup" syntax is only supported by recent versions of
NASM, but that's not important.) However, I'd prefer to use some calculation
to get NASM to reliably fill the buffer, such as:
entry: jmp trans
times 1024 - ($ - entry) db 0
Alternatively, you could use my fill macro [10] like this:
entry: fill 1024, 0, jmp trans
(Also, as I think you already suggested in this thread, for optimising the
transient executable size you could put one of the tables into this buffer to
save 1 KiB at the end of the executable. (Just the jump needs to stay, you
could re-initialise it to hold the correct 3byte for the table start later.)
Or stash some of the messages in there, as long as they're shorter than the 1
KiB size.)
(I've more recently done this with the CP437 table, because it's the
default.)
You do not use an IBM Interrupt Sharing Protocol (IISP) [11] header for your
interrupt hook. Therefore, you could optimise this part a bit, from:
old2F: dd 0xFFFF0000
...
.1: jmp far [cs:old2F]
Into this:
.1: jmp 0:0
old2F equ $ - 4
This is some self-modifying code (SMC) to stash the downlink into an
immediate far jump instruction, instead of using the indirect far jump to
refer to a different memory location in your code segment. The dollar sign is
used in the equate to denote the current assembly position after the 5-byte
instruction; it is offset by minus four so as to address the far pointer in
the instruction's encoding. (As mentioned, you cannot do this if you use a
standard IISP header, because that has a "jmp short $+18" (EBh 10h)
instruction right in front of the downlink field.)
I believe it was from analyzing some MS-DOS 2.0 code that I got the
technique I used here.
Next, you're using "or al, al" to check a register for zero. However, it is
more idiomatic [12] to use "test al, al" instead, which right away hints (to
a reader or even to the processor) that no change of the register occurs.
Also not sure where I got the "or" idiom, but I know that it doesn't alter
the register data.
Additionally, you're using two instructions of the test or compare types to
dispatch down three different paths. (These are handling the function 00h
call, or the function 01h call, or anything else.) One comparison instruction
suffices to do that however. Observe:
new2F:
...
cmp al, 1
ja .chain
je .function_01
.function_00:
Hm, that's true. Hadn't thought of that.
Other than your earlier use of "dup" syntax, you are also using "mov word
ds:[bx], entry". The segment override outside the brackets is another MASMism
that NASM has recently learned to support. I prefer the segment override
within the brackets however.
It makes more sense with [ds:bx], yeah.
(Regarding a here-deleted convo regarding EMS and XMS memory)
I've been thinking about how to implement other DOS commands - I'm
basically trying to create a compact reimplementation of the MS-DOS 6.21
userland, more or less, and I know I'm in way over my head - and trying to
figure out XMS and EMS has been something I've been wracking my brain over
for an idea to implement XCOPY, by creating a series of "packets" with
commands like "create directory", "open file", "write to file", etc., and
store as many of these "packets" in RAM, including XMS and EMS, as
possible before dumping the data out to disk.
Also, I've been hacking on MS-DOS 2 DEBUG trying to figure out how to plug
in MS-DOS 4 functions (EMS support and read/write on BIGFAT devices)
without success, but that's another matter ;p
-uso.
_______________________________________________
Freedos-devel mailing list
Freedos-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freedos-devel