Recent

Author Topic: How to read shortstring from a far pointer in i8086 msdos small memory model?  (Read 510 times)

ecm

  • New Member
  • *
  • Posts: 12
I'm still trying to port LZEXE to build with FreePascal for the i8086 msdos target. I already mentioned the problem with reading from a far pointer in my prior thread.

The cmdline.pas tries to read the DOS command line (up to 126 bytes preceded by a count byte) from the PSP segment, offset 0080h. The PSP segment is easily found in the variable Prefixseg. Instead of this working, it always reads data from the near data segment at offset 0080h.

Is there a way to make it read from the PSP segment? I would ideally not need to change the memory model to one other than "small".

Here's a log of a test I did. The last run shows that the cmd variable is read from the near data segment, offset 0080h, rather than as intended from the PSP segment. PtrInt always returns 128 (ie 0080h), not the expected far address.

Code: [Select]
test$ dosemu -dumb -td -kt -q -quiet -K "$PWD" -E "ldebug test.exe foo bar baz"
About to Execute : ldebug test.exe foo bar baz
lDebug (2025-03-09)
-h psp
2B31  decimal: 11057
-g
Prefixseg = 11057
128
ptr:
128
FarPointer:

Program terminated normally (0000)
-q
test$ ./fpc.sh test.pas
Free Pascal Compiler version 3.2.2 [2021/05/17] for i8086
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: MS-DOS 16-bit real mode
Compiling test.pas
test.pas(10,10) Warning: Conversion between ordinals and pointers is not portable
test.pas(14,10) Warning: Conversion between ordinals and pointers is not portable
test.pas(9,7) Note: Call to subroutine "function Ptr(sel:Word;off:Word):^untyped;far;" marked as inline is not inlined
Linking test.exe
18 lines compiled, 0.0 sec, 14186 bytes code, 466 bytes data
2 warning(s) issued
1 note(s) issued
test$ dosemu -dumb -td -kt -q -quiet -K "$PWD" -E "ldebug test.exe foo bar baz"
About to Execute : ldebug test.exe foo bar baz
lDebug (2025-03-09)
-bp at ptr ri21p when ah == 40
-g
Hit permanent breakpoint 00
AX=4000 BX=0001 CX=0013 DX=03CC SP=FEA2 BP=2ACD SI=FEB6 DI=0146
DS=2EB8 ES=0A81 SS=2EB8 CS=F10E IP=008A NV UP DI NG NZ NA PE NC
F10E:008A EB10              jmp     009C
-d ds:dx l cx
2EB8:03C0                         -            50 72 65 66             Pref
2EB8:03D0  69 78 73 65 67 20 3D 20-31 31 30 35 37 0D 0A    ixseg = 11057..
-g
Prefixseg = 11057
Hit permanent breakpoint 00
AX=4013 BX=0001 CX=0005 DX=03CC SP=FEA2 BP=2ACD SI=FEB6 DI=0146
DS=2EB8 ES=0A81 SS=2EB8 CS=F10E IP=008A NV UP DI NG NZ NA PE NC
F10E:008A EB10              jmp     009C
-d ds:dx l cx
2EB8:03C0                         -            31 32 38 0D             128.
2EB8:03D0  0A                     -                        .
-g
128
Hit permanent breakpoint 00
AX=4005 BX=0001 CX=0007 DX=03CC SP=FEA2 BP=2ACD SI=FEB6 DI=0146
DS=2EB8 ES=0A81 SS=2EB8 CS=F10E IP=008A NV UP DI NG NZ NA PE NC
F10E:008A EB10              jmp     009C
-d ds:dx l cx
2EB8:03C0                         -            70 74 72 3A             ptr:
2EB8:03D0  20 0D 0A               -                         ..
-g
ptr:
Hit permanent breakpoint 00
AX=4007 BX=0001 CX=0005 DX=03CC SP=FEA2 BP=2ACD SI=FEB6 DI=0146
DS=2EB8 ES=0A81 SS=2EB8 CS=F10E IP=008A NV UP DI NG NZ NA PE NC
F10E:008A EB10              jmp     009C
-d ds:dx l cx
2EB8:03C0                         -            31 32 38 0D             128.
2EB8:03D0  0A                     -                        .
-g
128
Hit permanent breakpoint 00
AX=4005 BX=0001 CX=000E DX=03CC SP=FEA2 BP=2ACD SI=FEB6 DI=0146
DS=2EB8 ES=0A81 SS=2EB8 CS=F10E IP=008A NV UP DI NG NZ NA PE NC
F10E:008A EB10              jmp     009C
-d ds:dx l cx
2EB8:03C0                         -            46 61 72 50             FarP
2EB8:03D0  6F 69 6E 74 65 72 3A 20-0D 0A                   ointer: ..
-d ds:0
2EB8:0000  01 01 01 01 01 01 01 01-01 01 01 01 01 01 01 01 ................
2EB8:0010  01 01 01 01 01 01 01 01-01 01 01 01 01 01 01 01 ................
2EB8:0020  00 00 4D 65 6D 6F 72 79-20 61 6C 6C 6F 63 61 74 ..Memory allocat
2EB8:0030  69 6F 6E 20 65 72 72 6F-72 0D 0A 24 4E 6F 74 20 ion error..$Not
2EB8:0040  65 6E 6F 75 67 68 20 6D-65 6D 6F 72 79 0D 0A 24 enough memory..$
2EB8:0050  E0 19 00 10 00 10 02 00-00 00 32 13 00 00 01 00 ..........2.....
2EB8:0060  00 00 00 00 8B 13 00 00-00 00 08 00 00 00 30 31 ..............01
2EB8:0070  32 33 34 35 36 37 38 39-41 42 43 44 45 46 10 00 23456789ABCDEF..
-
2EB8:0080  00 00 00 00 00 49 18 FA-19 69 1A 81 1A B1 1A BA .....I...i......
2EB8:0090  1E 00 00 00 00 00 00 D2-1E 7D 1F 00 D4 09 D4 09 .........}......
2EB8:00A0  00 F0 D4 09 01 00 01 00-B8 22 00 00 03 00 01 00 ........."......
2EB8:00B0  01 00 01 00 00 00 15 34-1F 34 29 34 14 00 00 00 .......4.4)4....
2EB8:00C0  00 00 00 80 00 00 00 00-00 10 00 00 00 00 00 00 ................
2EB8:00D0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 0C 50 ...............P
2EB8:00E0  72 65 66 69 78 73 65 67-20 3D 20 00 05 70 74 72 refixseg = ..ptr
2EB8:00F0  3A 20 00 00 0C 46 61 72-50 6F 69 6E 74 65 72 3A : ...FarPointer:
-g
FarPointer:

Program terminated normally (0000)
-q
test$ cat fpc.sh
#! /bin/bash

MYFPCDIR="$(dirname "$0")"
"$MYFPCDIR"/bin/ppcross8086 -vi -Tmsdos -WmSmall \
 -Fu"$MYFPCDIR"/lib/fpc/3.2.2/units/msdos/8086-small/rtl \
 "$@"
test$ cat test.pas

program test;

var
        cmd:string[127];
        p:FarPointer;
begin
        writeln('Prefixseg = ',Prefixseg);
        p := ptr(Prefixseg,$80);
        writeln(PtrInt(p));
        cmd:=shortstring(p^);
        writeln('ptr: ' + cmd);
        p := FarPointer(Prefixseg * $10000 + $80);
        writeln(PtrInt(p));
        cmd:=shortstring(p^);
        writeln('FarPointer: ' + cmd);
        halt(0);
end.
test$ dosemu -dumb -td -kt -q -quiet -K "$PWD" -E "ldebug test.exe foo bar baz"
About to Execute : ldebug test.exe foo bar baz
lDebug (2025-03-09)
-d 2EB8:80
2EB8:0080  00 00 00 00 00 49 18 FA-19 69 1A 81 1A B1 1A BA .....I...i......
2EB8:0090  1E 00 00 00 00 00 00 D2-1E 7D 1F 00 00 00 00 00 .........}......
2EB8:00A0  00 00 00 00 01 00 00 00-B8 22 00 00 00 00 00 00 ........."......
2EB8:00B0  00 00 01 00 00 00 15 34-1F 34 29 34 14 00 00 00 .......4.4)4....
2EB8:00C0  00 00 00 80 00 00 00 00-00 10 00 00 00 00 00 00 ................
2EB8:00D0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 0C 50 ...............P
2EB8:00E0  72 65 66 69 78 73 65 67-20 3D 20 00 05 70 74 72 refixseg = ..ptr
2EB8:00F0  3A 20 00 00 0C 46 61 72-50 6F 69 6E 74 65 72 3A : ...FarPointer:
-e 2EB8:80 2 "l!"
-g
Prefixseg = 11057
128
ptr: l!
128
FarPointer: l!

Program terminated normally (0000)
-q
test$

ecm

  • New Member
  • *
  • Posts: 12
Switching to compact memory model solves this problem after all. Both the ptr and FarPointer solutions work to display the command line then. I would still be interested in doing it with the small memory model however.

Thaddy

  • Hero Member
  • *****
  • Posts: 17451
  • Ceterum censeo Trumpum esse delendum (Tnx Charlie)
No, you still need @S[1] as pointer to properly access it., S[0] contains the string length.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

ecm

  • New Member
  • *
  • Posts: 12
I'm not using "S[0]" anywhere though so I'm not sure what you mean. And as I wrote with compact or large model it just works.

I was pointed to https://wiki.freepascal.org/DOS/de by someone else. I didn't think to check this because I assumed it would just be a translation, but the content does differ some actually. It contains this very clear text:

Quote
Kompilieren muss man es noch mit

ppcross8086 -WmLarge helloworld.pas

-WmLarge ist wichtig, wen man das gleiche Speichermodell wie von Turbo-Pascal will. Macht sich besonders bemerkbar, wen man Speicher hin und her schiebt, zB. VRAM. In ASM macht es sich mit LDS und LES bemerkbar.

Translation:

Quote
One still has to compile it with

ppcross8086 -WmLarge helloworld.pas

-WmLarge is important if one wants the same memory model as TurboPascal. Makes itself particularly noteworthy if one moves memory around, eg VRAM. In ASM it is notable with LDS and LES.

This pointer made me look through the english page at https://wiki.freepascal.org/DOS again as well. And it contains a reference to TurboPascal's memory model as well:

Quote
Large

* Activated by the -WmLarge compiler option. This is the memory model used by Turbo Pascal version 4 and above

So my porting project should actually use compact or large model, not small. This also affects the heap allocations. LZEXE's packer wants to allocate from the heap, at most 128 kB (not KiB). But with small model, the fpc-compiled program cannot allocate more than about 55 kB.

(Also, trying to allocate twice exactly MaxAvail div 2 to two buffers fails with runtime error 203. I assume this is due to the heap management overhead.)

Thaddy

  • Hero Member
  • *****
  • Posts: 17451
  • Ceterum censeo Trumpum esse delendum (Tnx Charlie)
No it is due to mixing up stack and heap: I warned you!.
Manipulating the heap size is practically nonsense in most (99.999999%) cases, whereas manipulating the stack size is often a good thing.
BTW: I warned you about the 203 error too....
Also the length byte of a shortstring should be taken into account, so your short string content starts at s[1] .. has been for the past 40 years or so..
Pay attention....
Or do you simply do not understand?

If your heap is artificially shrunk you are very likely to get a heap error: you were naughty and the compiler told you so. Now leave the heap alone. I predicted that, sadly.
« Last Edit: June 21, 2025, 07:43:11 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

 

TinyPortal © 2005-2018