Просмотр исходного кода

Correct the runtime-library section, which had drifted out of date

Asked whether the runtime library was decompiled; checking the answer found the
SUMMARY.md section describing it was stale in ways that matter, including one
that contradicted a milestone two rows up.

  - "Current blob: 391 bytes" -- it is 436.
  - The entry offset table listed wrbool 109, wrreal 132, wrln 140, rdint 167,
    rdchar 268, rdbool 289, rdln 335 and wrtinl 148.  Measured, they are 111,
    136, 144, 171, 279, 302, 350 and 152: six of the fourteen entries had moved
    as the blob grew, and only four were still right.
  - "37 branch targets" -- 38.
  - "It has still never executed."  It has: rt_exec.py calls all fourteen
    entries under qemu, 36 cases, all passing, and that is what caught wrchar
    and wrbool destroying the caller's BP.  This is the sentence that needed
    fixing most, because a reader would reasonably conclude from it that the
    runtime is unverified.
  - The known-limit arithmetic "rtSz + 1000H (391 + 4096 = 4481)" and "every
    fixture is at 4491 or 4493 bytes".  With the runtime at 436 the data base is
    4532 and the images run 4539..4547.

All of it re-derived from `rt_exec.py --probe` and `check_runtime.py` rather
than adjusted to look plausible, and the table now says so, because a restated
constant that has drifted is the exact failure this project already made twice:
run_com_tests.sh and comtest.py both hard-coded RT_SZ = 391 and reported 30
false failures when the runtime outgrew it.  That story stays at line 241; it is
the reason the checkers locate the runtime by signature instead.

Two stale comments fixed in passing:

  - Compiler.mod:3273 "cannot happen: rt is 391" -- inside a Modula-2 comment,
    so no behaviour change, but it is the sort of number that gets quoted.
  - CompileTest.mod's DumpImage said "the runtime's own 391 bytes".  That code
    already DERIVES the size (`rtSz := ImageBytes () - CodeBytes ()`), so only
    the comment had drifted; it now names no number at all.

Verified: run_all.sh 12/12 ALL PASS, compile matrix 34/34.

NOT fixed here, and worth its own commit: tests/check_framedisp.py hard-codes
RT_SZ = 391 too, so its byte sweep starts at image offset 394 -- 61 bytes
inside the runtime's tail and across the 16-byte program header, which contains
the ASCII of "TRUE$"/"FALSE$".  Measured: sweeping from the true code start
(455) finds exactly the same [BP+off] accesses on both fixtures that use it, so
it passes for the right reasons today -- by luck, not by construction, since a
desynchronising header would silently blind it.  Fixing it properly means
deriving the region, and that logic now lives in two checkers; a third copy is
the liability the project rules warn about, so it wants a shared module rather
than another literal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Eric Streit 1 неделя назад
Родитель
Сommit
e09a08a877
3 измененных файлов с 32 добавлено и 17 удалено
  1. 27 13
      SUMMARY.md
  2. 1 1
      shell/Compiler.mod
  3. 4 3
      shell/tests/CompileTest.mod

+ 27 - 13
SUMMARY.md

@@ -692,17 +692,25 @@ initialised past it (`MOV pc,#$2D7C`). Same shape here, and now actually done:
 image-absolute. **No relocation pass is needed** — worth having paid for, since
 a linker that has to walk fixups is a linker that can get them wrong.
 
-Current blob: **391 bytes**, 14 entries, 37 branch targets, offsets read back
+Current blob: **436 bytes**, 14 entries, 38 branch targets, offsets read back
 out of the assembled bytes by `tests/check_runtime.py` rather than asserted by
 hand:
 
 | entry | offset | entry | offset | entry | offset |
 |---|---|---|---|---|---|
-| `initmem` | 0 | `wrint` | 36 | `rdint` | 167 |
-| `progend` | 28 | `wrchar` | 97 | `rdchar` | 268 |
-| `stackchk` | 35 | `wrbool` | 109 | `rdbool` | 289 |
-| `halt` | 28 | `wrreal` | 132 | `rdln` | 335 |
-| | | `wrln` | 140 | `wrtinl` | 148 |
+| `initmem` | 0 | `wrint` | 36 | `rdint` | 171 |
+| `progend` | 28 | `wrchar` | 97 | `rdchar` | 279 |
+| `stackchk` | 35 | `wrbool` | 111 | `rdbool` | 302 |
+| `halt` | 28 | `wrreal` | 136 | `rdln` | 350 |
+| | | `wrln` | 144 | `wrtinl` | 152 |
+
+Every number in that table is measured, and that is the point: it was last
+correct when the blob was 391 bytes, and the entries quietly moved as it grew
+to 436 — six of the fourteen offsets in the previous version of this table were
+stale, and the size was stale too. A restated constant that has drifted is
+worse than a derived one, which is why the compiler asks
+`Runtime.RT_Entry` instead (below) and why the checkers locate the runtime by
+its own signature rather than by a literal.
 
 The `TU_*` constants in `Compiler.mod` are **assigned from
 `Runtime.RT_Entry` in `Inittur`**, not written down, so a runtime edit that
@@ -753,10 +761,15 @@ Two label-name plus fixup list: `rel8`, `rel16` and runtime-data addresses are
 all patched after the blob is placed, so nothing depends on a hand-computed
 displacement.
 
-**It has still never executed.** The encodings are now audited, golden-pinned
-and non-vacuity-proved, which is a much stronger static claim than "it
-assembles" — but a static check cannot tell you the code *works*, only that it
-is what was intended. See the executor section.
+**It executes.** Every entry is called directly under qemu by
+`tests/rt_exec.py` — 36 cases, all passing — with the register contract each
+entry must honour stated rather than assumed, which is how `wrchar` and
+`wrbool` were caught destroying the caller's BP. That milestone
+(`v-TP3-BP-CONTRACT`) is the reason this paragraph no longer says the runtime
+has never run; it did, for two releases. What is *not* covered is what a direct
+call cannot reach: the runtime is still measured entry-by-entry rather than
+against TP3's own binary, so this is a compatibility claim and not a
+byte-for-byte reproduction of the original's.
 
 ### The program image — `shell/Linker.mod`
 
@@ -782,9 +795,10 @@ assertion, rather than asking the compiler where it thinks the header is.
 last dot, padded with a zero gap to `max(pc, dc)`; its stack sits at the segment
 top (`SS = SP = CS:FFFE`), which is where DOS puts it.
 
-**Known limit:** the data area starts at a fixed `rtSz + 1000H` (391 + 4096 =
-4481), so a program whose code exceeds 4 KiB runs into its own data. Every
-fixture is at 4491 or 4493 bytes. Documented rather than fixed, because the
+**Known limit:** the data area starts at a fixed `rtSz + 1000H` (436 + 4096 =
+4532), so a program whose code exceeds 4 KiB runs into its own data. Every
+fixture's image is between 4539 and 4547 bytes. Documented rather than fixed,
+because the
 original has the same fixed-offset behaviour.
 
 ### String literals — `writeln('hi')`

+ 1 - 1
shell/Compiler.mod

@@ -3270,7 +3270,7 @@ BEGIN
    RT_Build (EntSize) ;
    rt := RT_Size () ;
    IF rt >= MaxCode THEN
-      Err (EMemOvf) ;                 (* cannot happen: rt is 391 *)
+      Err (EMemOvf) ;                 (* cannot happen: rt is 436 *)
       RETURN
    END ;
    (* The entry jump, at image offset 0.  See the layout note above: a DOS

+ 4 - 3
shell/tests/CompileTest.mod

@@ -266,9 +266,10 @@ END DumpCode ;
 
 PROCEDURE DumpImage ;
 (* The whole linked image - [entry JMP][runtime][program header][program code] -
-   which is what a .COM would actually contain.  The runtime's own 391 bytes
-   are shown only at the head and the tail: enough to prove the blob is really
-   in there, without burying the program in 24 lines of library. *)
+   which is what a .COM would actually contain.  The runtime's own bytes
+   (rtSz below, derived rather than written down) are shown only at the head
+   and the tail: enough to prove the blob is really in there, without burying
+   the program in 28 lines of library. *)
 VAR i, n, rtSz, total, from, lim : CARDINAL ;
     hx : ARRAY [0..1] OF CHAR ;
 BEGIN