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:
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:
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:
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.)