RtProbe.mod 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. MODULE RtProbe ;
  2. (* Dump the assembled runtime: size, entry offsets, hex. Kept separate from
  3. CompileTest so the library can be checked on its own, before the compiler
  4. is wired to it.
  5. The IMAGE OFFSET the blob will occupy is read from the first line of stdin,
  6. as a decimal number. "0" - or no input at all, which is what every
  7. standalone caller gives it - reproduces the original behaviour: entries and
  8. internal data addresses come out blob-relative, which is what
  9. check_runtime.py, rt_exec.py and tests/runtime.golden all want.
  10. The parameter exists because the base is not cosmetic. FixUp bakes
  11. dataAt + rtBase + val + LoadBias into every absolute data address the
  12. library contains, so a blob built for base 0 and then copied to image
  13. offset 0x200 has every string pointer 0x200 too low - and that failure is
  14. silent: wrln would walk a $-terminated string from the wrong place and keep
  15. going through whatever bytes it finds. Emitting the bytes is base
  16. independent; only the addresses are not. *)
  17. FROM Posix IMPORT read, write ;
  18. FROM Runtime IMPORT RT_Build, RT_Size, RT_Byte, RT_Entry, RT_CodeEnd ;
  19. FROM SYSTEM IMPORT ADR, BYTE ;
  20. VAR
  21. c : CHAR ;
  22. PROCEDURE GetBase () : CARDINAL ;
  23. (* First line of stdin, decimal. 0 on EOF, on a line that is not a number, or
  24. on no input at all - so a caller that passes nothing gets base 0 and the
  25. historical output. One byte at a time, because a line is short and this
  26. keeps the module free of buffering that could swallow a caller's stdin. *)
  27. VAR
  28. ch : BYTE ;
  29. v : CARDINAL ;
  30. r : LONGINT ;
  31. more : BOOLEAN ;
  32. BEGIN
  33. v := 0 ;
  34. more := TRUE ;
  35. WHILE more DO
  36. r := read (0, ADR (ch), 1) ;
  37. IF r # 1 THEN
  38. more := FALSE
  39. ELSIF (ch < 48) OR (ch > 57) THEN
  40. more := FALSE (* newline, or junk: the line ends *)
  41. ELSE
  42. (* VAL, because ISO Modula-2 has no arithmetic between a BYTE and a
  43. CARDINAL, and a plain `ch - 48' is exactly the sort of
  44. mixed-size expression that silently wraps when it is small. *)
  45. v := v * 10 + (VAL (CARDINAL, ch) - 48)
  46. END
  47. END ;
  48. RETURN v
  49. END GetBase ;
  50. PROCEDURE PC (ch : CHAR ) ;
  51. VAR n : LONGINT ;
  52. BEGIN
  53. n := write (1, ADR (ch), 1)
  54. END PC ;
  55. PROCEDURE PS (s : ARRAY OF CHAR ) ;
  56. VAR i : CARDINAL ; n : LONGINT ;
  57. BEGIN
  58. i := 0 ;
  59. WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO
  60. n := write (1, ADR (s [i]), 1) ;
  61. INC (i)
  62. END
  63. END PS ;
  64. PROCEDURE PCARD (n : CARDINAL ) ;
  65. VAR d : ARRAY [0..9] OF CHAR ; i : CARDINAL ;
  66. BEGIN
  67. IF n = 0 THEN
  68. PC ("0")
  69. ELSE
  70. i := 0 ;
  71. WHILE n > 0 DO
  72. d [i] := CHR (ORD ("0") + (n MOD 10)) ;
  73. n := n DIV 10 ;
  74. INC (i)
  75. END ;
  76. WHILE i > 0 DO
  77. DEC (i) ;
  78. PC (d [i])
  79. END
  80. END
  81. END PCARD ;
  82. PROCEDURE NL ; BEGIN PC (CHR (13)) ; PC (CHR (10)) END NL ;
  83. PROCEDURE PHEX (b : CARDINAL ) ;
  84. VAR d : CARDINAL ;
  85. BEGIN
  86. d := b DIV 16 ;
  87. IF d < 10 THEN PC (CHR (ORD ("0") + d)) ELSE PC (CHR (ORD ("A") + d - 10)) END ;
  88. d := b MOD 16 ;
  89. IF d < 10 THEN PC (CHR (ORD ("0") + d)) ELSE PC (CHR (ORD ("A") + d - 10)) END
  90. END PHEX ;
  91. PROCEDURE PENT (i : CARDINAL ; name : ARRAY OF CHAR ) ;
  92. BEGIN
  93. PS (" entry ") ; PCARD (i) ; PS (" = ") ; PCARD (RT_Entry (i)) ;
  94. PS (" (") ; PS (name) ; PS (")") ; NL
  95. END PENT ;
  96. PROCEDURE Main ;
  97. VAR i, n, base : CARDINAL ;
  98. names : ARRAY [0..13] OF ARRAY [0..15] OF CHAR ;
  99. BEGIN
  100. base := GetBase () ;
  101. RT_Build (base) ;
  102. (* "base=0" is printed even when it is 0, because a caller that forgets to
  103. redirect stdin would otherwise get base 0 by accident and no evidence of
  104. it. The entries below are then IMAGE-ABSOLUTE, and the last one line
  105. gives the address the one-character pushback slot lives at, so a harness
  106. that needs to clear it does not have to recompute FixUp's arithmetic. *)
  107. PS ("base=") ; PCARD (base) ; NL ;
  108. PCARD (RT_Size ()) ; PS (" bytes") ; NL ;
  109. PS ("code ends at ") ; PCARD (RT_CodeEnd ()) ; NL ;
  110. i := 0 ;
  111. WHILE i <= 13 DO
  112. names [i] := "" ;
  113. INC (i)
  114. END ;
  115. names [0] := "initmem" ; names [1] := "progend" ; names [2] := "stackchk" ;
  116. names [3] := "wrint" ; names [4] := "wrchar" ; names [5] := "wrbool" ;
  117. names [6] := "wrreal" ; names [7] := "wrln" ; names [8] := "rdint" ;
  118. names [9] := "rdchar" ; names [10] := "rdbool" ; names [11] := "rdln" ;
  119. names [12] := "halt" ; names [13] := "wrtinl" ;
  120. i := 0 ;
  121. WHILE i <= 13 DO
  122. PENT (i, names [i]) ;
  123. INC (i)
  124. END ;
  125. PS (" hex:") ; NL ;
  126. i := 0 ;
  127. WHILE i < RT_Size () DO
  128. (* eight hex digits of the 32-bit offset, one byte per PHEX call
  129. (PHEX prints two digits), most significant byte first *)
  130. PHEX ((i DIV 16777216) MOD 256) ;
  131. PHEX ((i DIV 65536) MOD 256) ;
  132. PHEX ((i DIV 256) MOD 256) ;
  133. PHEX (i MOD 256) ;
  134. PS (" ") ;
  135. n := 0 ;
  136. WHILE (n < 16) AND (i + n < RT_Size ()) DO
  137. PHEX (VAL (CARDINAL, RT_Byte (i + n))) ;
  138. PC (" ") ;
  139. INC (n)
  140. END ;
  141. NL ;
  142. i := i + 16
  143. END
  144. END Main ;
  145. BEGIN
  146. Main
  147. END RtProbe.