DEFINITION MODULE Runtime ; (* 8086 runtime library for TP3-compiled programs. The original embeds its runtime in the compiler's own code segment and copies it to the front of the generated code buffer (TPSRC7 "copyrt": "MOV CX,#start / REPZ MOVS.B" with SI=DI=0, then "MOV pc,#$2D7C" so the generated program starts past it; the .COM writer emits the runtime as a block ahead of the program). Same shape here: RT_Build assembles the library into rt[0..RT_Size-1], the compiler copies it to the front of its code buffer (behind the entry JMP) and starts pc/dc past it, so the runtime's own data lives at low, link-time-constant addresses and needs no relocation. The "front" is now at RT_Build's `base' rather than at 0. Entry offsets are *derived* from where the code actually lands, not hardcoded - see RT_Entry. Everything the compiler calls is reached by a relative CALL, and both sides shift by the same runtime size, so the displacement arithmetic in EmCall is unaffected by the runtime being prepended. *) FROM SYSTEM IMPORT BYTE ; CONST (* entry selectors for RT_Entry *) E_InitMem = 0 ; E_ProgEnd = 1 ; E_StackChk = 2 ; E_WrInt = 3 ; E_WrChar = 4 ; E_WrBool = 5 ; E_WrReal = 6 ; E_WrLn = 7 ; E_RdInt = 8 ; E_RdChar = 9 ; E_RdBool = 10 ; E_RdLn = 11 ; E_Halt = 12 ; E_WrInl = 13 ; (* Where a .COM's first byte ends up. DOS loads a .COM at CS:0100 (the 100 bytes below are the PSP), and CS = DS, so an image offset K is at DS:(K + 0100h). EVERY address baked into the image as an absolute literal must therefore carry this. It is here, in Runtime, because FixUp needs it and Compiler needs it, and one constant in one place is the only way a six-site bias can stay consistent - see the long note in Runtime.mod, which also records how the failure looks: the program runs, prints its first field, and then walks a $ that is 100h too low through the runtime's own code. *) LoadBias = 100H ; PROCEDURE RT_Build (base : CARDINAL) ; (* assemble the runtime; idempotent, called once at Compile time. `base' is the IMAGE OFFSET the runtime blob will be copied to. It is a parameter rather than an assumption because the image begins with a three-byte entry JMP, so the runtime does not sit at image offset 0 - and every address the runtime bakes into its own code (its data block, and the entry offsets RT_Entry hands back) has to be biased by it. The emitted BYTES are the same for any base, because both are computed after assembly, so the standalone probes and tests/runtime.golden pass 0 and are unaffected. NOTE, because it has already cost time: this .def file is HAND-MAINTAINED. gm2 reads X.def to resolve `FROM X IMPORT ...' and checks the implementation against it, but it does NOT rewrite it - a successful compile leaves X.def byte-identical, and deleting it makes gm2 fail with "the file containing the definition module « X » cannot be found" rather than regenerate it. So an interface change means editing Runtime.def by hand in the same commit, exactly as Editor.def was edited to add Editor.GotoOffset. Keep such changes ADDITIVE where possible: an unchanged procedure's declaration does not need re-typing, so only the lines that actually moved have to be right. *) PROCEDURE RT_Size () : CARDINAL ; (* size of the runtime in bytes - the offset at which the generated program starts inside the image *) PROCEDURE RT_Byte (i : CARDINAL) : BYTE ; (* i-th runtime byte, 0 past the end, for hex dumps *) PROCEDURE RT_Entry (i : CARDINAL) : CARDINAL ; (* offset of entry i (an E_* selector) inside the runtime; 0 if unknown *) PROCEDURE RT_CodeEnd () : CARDINAL ; (* offset where the code stops and the runtime's data block starts. Bytes from here on are strings and scratch, so disassembling them is meaningless; tests use this to sweep the code region only. *) END Runtime.