BIN.ob07 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. (*
  2. BSD 2-Clause License
  3. Copyright (c) 2018-2020, Anton Krotov
  4. All rights reserved.
  5. *)
  6. MODULE BIN;
  7. IMPORT LISTS, CHL := CHUNKLISTS, ARITH, UTILS;
  8. CONST
  9. RCODE* = 0; PICCODE* = RCODE + 1;
  10. RDATA* = 2; PICDATA* = RDATA + 1;
  11. RBSS* = 4; PICBSS* = RBSS + 1;
  12. RIMP* = 6; PICIMP* = RIMP + 1;
  13. IMPTAB* = 8;
  14. TYPE
  15. RELOC* = POINTER TO RECORD (LISTS.ITEM)
  16. opcode*: INTEGER;
  17. offset*: INTEGER
  18. END;
  19. IMPRT* = POINTER TO RECORD (LISTS.ITEM)
  20. nameoffs*: INTEGER;
  21. label*: INTEGER;
  22. OriginalFirstThunk*,
  23. FirstThunk*: INTEGER
  24. END;
  25. EXPRT* = POINTER TO RECORD (LISTS.ITEM)
  26. nameoffs*: INTEGER;
  27. label*: INTEGER
  28. END;
  29. PROGRAM* = POINTER TO RECORD
  30. code*: CHL.BYTELIST;
  31. data*: CHL.BYTELIST;
  32. labels: CHL.INTLIST;
  33. bss*: INTEGER;
  34. stack*: INTEGER;
  35. vmajor*,
  36. vminor*: WCHAR;
  37. modname*: INTEGER;
  38. _import*: CHL.BYTELIST;
  39. export*: CHL.BYTELIST;
  40. rel_list*: LISTS.LIST;
  41. imp_list*: LISTS.LIST;
  42. exp_list*: LISTS.LIST
  43. END;
  44. PROCEDURE create* (NumberOfLabels: INTEGER): PROGRAM;
  45. VAR
  46. program: PROGRAM;
  47. i: INTEGER;
  48. BEGIN
  49. NEW(program);
  50. program.bss := 0;
  51. program.labels := CHL.CreateIntList();
  52. FOR i := 0 TO NumberOfLabels - 1 DO
  53. CHL.PushInt(program.labels, 0)
  54. END;
  55. program.rel_list := LISTS.create(NIL);
  56. program.imp_list := LISTS.create(NIL);
  57. program.exp_list := LISTS.create(NIL);
  58. program.data := CHL.CreateByteList();
  59. program.code := CHL.CreateByteList();
  60. program._import := CHL.CreateByteList();
  61. program.export := CHL.CreateByteList()
  62. RETURN program
  63. END create;
  64. PROCEDURE SetParams* (program: PROGRAM; bss, stack: INTEGER; vmajor, vminor: WCHAR);
  65. BEGIN
  66. program.bss := bss;
  67. program.stack := stack;
  68. program.vmajor := vmajor;
  69. program.vminor := vminor
  70. END SetParams;
  71. PROCEDURE PutReloc* (program: PROGRAM; opcode: INTEGER);
  72. VAR
  73. cmd: RELOC;
  74. BEGIN
  75. NEW(cmd);
  76. cmd.opcode := opcode;
  77. cmd.offset := CHL.Length(program.code);
  78. LISTS.push(program.rel_list, cmd)
  79. END PutReloc;
  80. PROCEDURE PutData* (program: PROGRAM; b: BYTE);
  81. BEGIN
  82. CHL.PushByte(program.data, b)
  83. END PutData;
  84. PROCEDURE get32le* (_array: CHL.BYTELIST; idx: INTEGER): INTEGER;
  85. VAR
  86. i: INTEGER;
  87. x: INTEGER;
  88. BEGIN
  89. x := 0;
  90. FOR i := 3 TO 0 BY -1 DO
  91. x := LSL(x, 8) + CHL.GetByte(_array, idx + i)
  92. END;
  93. IF UTILS.bit_depth = 64 THEN
  94. x := LSL(x, 16);
  95. x := LSL(x, 16);
  96. x := ASR(x, 16);
  97. x := ASR(x, 16)
  98. END
  99. RETURN x
  100. END get32le;
  101. PROCEDURE put32le* (_array: CHL.BYTELIST; idx: INTEGER; x: INTEGER);
  102. VAR
  103. i: INTEGER;
  104. BEGIN
  105. FOR i := 0 TO 3 DO
  106. CHL.SetByte(_array, idx + i, UTILS.Byte(x, i))
  107. END
  108. END put32le;
  109. PROCEDURE PutData32LE* (program: PROGRAM; x: INTEGER);
  110. VAR
  111. i: INTEGER;
  112. BEGIN
  113. FOR i := 0 TO 3 DO
  114. CHL.PushByte(program.data, UTILS.Byte(x, i))
  115. END
  116. END PutData32LE;
  117. PROCEDURE PutData64LE* (program: PROGRAM; x: INTEGER);
  118. VAR
  119. i: INTEGER;
  120. BEGIN
  121. FOR i := 0 TO 7 DO
  122. CHL.PushByte(program.data, UTILS.Byte(x, i))
  123. END
  124. END PutData64LE;
  125. PROCEDURE PutDataStr* (program: PROGRAM; s: ARRAY OF CHAR);
  126. VAR
  127. i: INTEGER;
  128. BEGIN
  129. i := 0;
  130. WHILE s[i] # 0X DO
  131. PutData(program, ORD(s[i]));
  132. INC(i)
  133. END
  134. END PutDataStr;
  135. PROCEDURE PutCode* (program: PROGRAM; b: BYTE);
  136. BEGIN
  137. CHL.PushByte(program.code, b)
  138. END PutCode;
  139. PROCEDURE PutCode32LE* (program: PROGRAM; x: INTEGER);
  140. VAR
  141. i: INTEGER;
  142. BEGIN
  143. FOR i := 0 TO 3 DO
  144. CHL.PushByte(program.code, UTILS.Byte(x, i))
  145. END
  146. END PutCode32LE;
  147. PROCEDURE PutCode16LE* (program: PROGRAM; x: INTEGER);
  148. BEGIN
  149. CHL.PushByte(program.code, UTILS.Byte(x, 0));
  150. CHL.PushByte(program.code, UTILS.Byte(x, 1))
  151. END PutCode16LE;
  152. PROCEDURE SetLabel* (program: PROGRAM; label, offset: INTEGER);
  153. BEGIN
  154. CHL.SetInt(program.labels, label, offset)
  155. END SetLabel;
  156. PROCEDURE Import* (program: PROGRAM; name: ARRAY OF CHAR; label: INTEGER);
  157. VAR
  158. imp: IMPRT;
  159. BEGIN
  160. CHL.PushByte(program._import, 0);
  161. CHL.PushByte(program._import, 0);
  162. IF ODD(CHL.Length(program._import)) THEN
  163. CHL.PushByte(program._import, 0)
  164. END;
  165. NEW(imp);
  166. imp.nameoffs := CHL.PushStr(program._import, name);
  167. imp.label := label;
  168. LISTS.push(program.imp_list, imp)
  169. END Import;
  170. PROCEDURE less (bytes: CHL.BYTELIST; a, b: EXPRT): BOOLEAN;
  171. VAR
  172. i, j: INTEGER;
  173. BEGIN
  174. i := a.nameoffs;
  175. j := b.nameoffs;
  176. WHILE (CHL.GetByte(bytes, i) # 0) & (CHL.GetByte(bytes, j) # 0) &
  177. (CHL.GetByte(bytes, i) = CHL.GetByte(bytes, j)) DO
  178. INC(i);
  179. INC(j)
  180. END
  181. RETURN CHL.GetByte(bytes, i) < CHL.GetByte(bytes, j)
  182. END less;
  183. PROCEDURE Export* (program: PROGRAM; name: ARRAY OF CHAR; label: INTEGER);
  184. VAR
  185. exp, cur: EXPRT;
  186. BEGIN
  187. NEW(exp);
  188. exp.label := CHL.GetInt(program.labels, label);
  189. exp.nameoffs := CHL.PushStr(program.export, name);
  190. cur := program.exp_list.first(EXPRT);
  191. WHILE (cur # NIL) & less(program.export, cur, exp) DO
  192. cur := cur.next(EXPRT)
  193. END;
  194. IF cur # NIL THEN
  195. IF cur.prev # NIL THEN
  196. LISTS.insert(program.exp_list, cur.prev, exp)
  197. ELSE
  198. LISTS.insertL(program.exp_list, cur, exp)
  199. END
  200. ELSE
  201. LISTS.push(program.exp_list, exp)
  202. END
  203. END Export;
  204. PROCEDURE GetIProc* (program: PROGRAM; n: INTEGER): IMPRT;
  205. VAR
  206. _import, res: IMPRT;
  207. BEGIN
  208. _import := program.imp_list.first(IMPRT);
  209. res := NIL;
  210. WHILE (_import # NIL) & (n >= 0) DO
  211. IF _import.label # 0 THEN
  212. res := _import;
  213. DEC(n)
  214. END;
  215. _import := _import.next(IMPRT)
  216. END;
  217. ASSERT(n = -1)
  218. RETURN res
  219. END GetIProc;
  220. PROCEDURE GetLabel* (program: PROGRAM; label: INTEGER): INTEGER;
  221. RETURN CHL.GetInt(program.labels, label)
  222. END GetLabel;
  223. PROCEDURE NewLabel* (program: PROGRAM);
  224. BEGIN
  225. CHL.PushInt(program.labels, 0)
  226. END NewLabel;
  227. PROCEDURE fixup* (program: PROGRAM);
  228. VAR
  229. rel: RELOC;
  230. imp: IMPRT;
  231. nproc: INTEGER;
  232. L: INTEGER;
  233. BEGIN
  234. nproc := 0;
  235. imp := program.imp_list.first(IMPRT);
  236. WHILE imp # NIL DO
  237. IF imp.label # 0 THEN
  238. CHL.SetInt(program.labels, imp.label, nproc);
  239. INC(nproc)
  240. END;
  241. imp := imp.next(IMPRT)
  242. END;
  243. rel := program.rel_list.first(RELOC);
  244. WHILE rel # NIL DO
  245. IF rel.opcode IN {RIMP, PICIMP} THEN
  246. L := get32le(program.code, rel.offset);
  247. put32le(program.code, rel.offset, GetLabel(program, L))
  248. END;
  249. rel := rel.next(RELOC)
  250. END
  251. END fixup;
  252. PROCEDURE InitArray* (VAR _array: ARRAY OF BYTE; VAR idx: INTEGER; hex: ARRAY OF CHAR);
  253. VAR
  254. i, k: INTEGER;
  255. PROCEDURE hexdgt (dgt: CHAR): INTEGER;
  256. VAR
  257. res: INTEGER;
  258. BEGIN
  259. IF dgt < "A" THEN
  260. res := ORD(dgt) - ORD("0")
  261. ELSE
  262. res := ORD(dgt) - ORD("A") + 10
  263. END
  264. RETURN res
  265. END hexdgt;
  266. BEGIN
  267. k := LENGTH(hex);
  268. ASSERT(~ODD(k));
  269. k := k DIV 2;
  270. FOR i := 0 TO k - 1 DO
  271. _array[i + idx] := hexdgt(hex[2 * i]) * 16 + hexdgt(hex[2 * i + 1])
  272. END;
  273. INC(idx, k)
  274. END InitArray;
  275. END BIN.