Linker.txt 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779
  1. MODULE Dev0Linker;
  2. (* THIS IS TEXT COPY OF Linker.odc *)
  3. (* DO NOT EDIT *)
  4. IMPORT
  5. Kernel, Files, (* Dates, Dialog, *) Strings,
  6. (* TextModels, TextViews, TextMappers,
  7. Log := StdLog, DevCommanders *) Console;
  8. CONST
  9. NewRecFP = 4E27A847H;
  10. NewArrFP = 76068C78H;
  11. ImageBase = 00400000H;
  12. ObjAlign = 1000H;
  13. FileAlign = 200H;
  14. HeaderSize = 400H;
  15. FixLen = 30000;
  16. OFdir = "Code";
  17. SYSdir = "System";
  18. RsrcDir = "Rsrc";
  19. WinDir = "Win";
  20. (* meta interface consts *)
  21. mConst = 1; mTyp = 2; mVar = 3; mProc = 4; mField = 5;
  22. mInternal = 1; mReadonly = 2; mExported = 4;
  23. (* fixup types *)
  24. absolute = 100; relative = 101; copy = 102; table = 103; tableend = 104;
  25. (* mod desc fields *)
  26. modOpts = 4; modRefcnt = 8; modTerm = 40; modNames = 84; modImports = 92; modExports = 96;
  27. (* A. V. Shiryaev: Scanner *)
  28. TMChar = 0; TMString = 1; TMInt = 2; TMEOT = 3;
  29. TYPE
  30. Name = ARRAY 40 OF SHORTCHAR;
  31. Export = POINTER TO RECORD
  32. next: Export;
  33. name: Name;
  34. adr: INTEGER
  35. END;
  36. Resource = POINTER TO RECORD
  37. next, local: Resource;
  38. typ, id, lid, size, pos, x, y: INTEGER;
  39. opts: SET;
  40. file: Files.File;
  41. name: Files.Name
  42. END;
  43. Module = POINTER TO RECORD
  44. next: Module;
  45. name: Files.Name;
  46. file: Files.File;
  47. hs, ms, ds, cs, vs, ni, ma, ca, va: INTEGER;
  48. dll, intf: BOOLEAN;
  49. exp: Export;
  50. imp: POINTER TO ARRAY OF Module;
  51. data: POINTER TO ARRAY OF BYTE;
  52. END;
  53. (* A. V. Shiryaev: Scanner *)
  54. ScanRider = RECORD
  55. s: POINTER TO ARRAY OF CHAR;
  56. i: INTEGER
  57. END;
  58. Scanner = RECORD
  59. rider: ScanRider;
  60. start, type: INTEGER;
  61. string: ARRAY 100 OF CHAR;
  62. char: CHAR;
  63. int: INTEGER
  64. END;
  65. VAR
  66. (*
  67. W: TextMappers.Formatter;
  68. *)
  69. Out: Files.File;
  70. R: Files.Reader;
  71. Ro: Files.Writer;
  72. error, isDll, isStatic, comLine: BOOLEAN;
  73. modList, kernel, main, last, impg, impd: Module;
  74. numMod, lastTerm: INTEGER;
  75. resList: Resource;
  76. numType, resHSize: INTEGER;
  77. numId: ARRAY 32 OF INTEGER;
  78. rsrcName: ARRAY 16 OF CHAR; (* name of resource file *)
  79. firstExp, lastExp: Export;
  80. entryPos, isPos, fixPos, himpPos, hexpPos, hrsrcPos, termPos: INTEGER;
  81. codePos, dataPos, conPos, rsrcPos, impPos, expPos, relPos: INTEGER;
  82. CodeSize, DataSize, ConSize, RsrcSize, ImpSize, ImpHSize, ExpSize, RelocSize, DllSize: INTEGER;
  83. CodeRva, DataRva, ConRva, RsrcRva, ImpRva, ExpRva, RelocRva, ImagesSize: INTEGER;
  84. CodeBase, DataBase, ConBase, maxCode, numImp, numExp, noffixup, timeStamp: INTEGER;
  85. newRec, newArr: Name;
  86. fixups: POINTER TO ARRAY OF INTEGER;
  87. code: POINTER TO ARRAY OF BYTE;
  88. atab: POINTER TO ARRAY OF INTEGER;
  89. ntab: POINTER TO ARRAY OF SHORTCHAR;
  90. (* A. V. Shiryaev: Console *)
  91. PROCEDURE WriteString (s: ARRAY OF CHAR);
  92. BEGIN
  93. Console.WriteStr(s)
  94. END WriteString;
  95. PROCEDURE WriteChar (c: CHAR);
  96. VAR s: ARRAY 2 OF CHAR;
  97. BEGIN
  98. s[0] := c; s[1] := 0X;
  99. Console.WriteStr(s)
  100. END WriteChar;
  101. PROCEDURE WriteSString (ss: ARRAY OF SHORTCHAR);
  102. BEGIN
  103. Console.WriteStr(ss$)
  104. END WriteSString;
  105. PROCEDURE WriteInt (x: INTEGER);
  106. VAR s: ARRAY 16 OF CHAR;
  107. BEGIN
  108. Strings.IntToString(x, s);
  109. Console.WriteStr(s)
  110. END WriteInt;
  111. PROCEDURE WriteLn;
  112. BEGIN
  113. Console.WriteLn
  114. END WriteLn;
  115. PROCEDURE FlushW;
  116. BEGIN
  117. END FlushW;
  118. (*
  119. PROCEDURE TimeStamp (): INTEGER; (* seconds since 1.1.1970 00:00:00 *)
  120. VAR a: INTEGER; t: Dates.Time; d: Dates.Date;
  121. BEGIN
  122. Dates.GetTime(t); Dates.GetDate(d);
  123. a := 12 * (d.year - 70) + d.month - 3;
  124. a := a DIV 12 * 1461 DIV 4 + (a MOD 12 * 153 + 2) DIV 5 + d.day + 59;
  125. RETURN ((a * 24 + t.hour) * 60 + t.minute) * 60 + t.second;
  126. END TimeStamp;
  127. *)
  128. PROCEDURE ThisFile (modname: ARRAY OF CHAR): Files.File;
  129. VAR dir, name: Files.Name; loc: Files.Locator; f: Files.File;
  130. BEGIN
  131. Kernel.SplitName(modname, dir, name);
  132. Kernel.MakeFileName(name, Kernel.objType);
  133. loc := Files.dir.This(dir); loc := loc.This(OFdir);
  134. f := Files.dir.Old(loc, name, TRUE);
  135. IF (f = NIL) & (dir = "") THEN
  136. loc := Files.dir.This(SYSdir); loc := loc.This(OFdir);
  137. f := Files.dir.Old(loc, name, TRUE)
  138. END;
  139. RETURN f
  140. END ThisFile;
  141. PROCEDURE ThisResFile (VAR name: Files.Name): Files.File;
  142. VAR loc: Files.Locator; f: Files.File;
  143. BEGIN
  144. f := Files.dir.Old(Files.dir.This(RsrcDir), name, TRUE);
  145. IF f = NIL THEN
  146. loc := Files.dir.This(WinDir); loc := loc.This(RsrcDir);
  147. f := Files.dir.Old(loc, name, TRUE);
  148. IF f = NIL THEN
  149. f := Files.dir.Old(Files.dir.This(""), name, TRUE)
  150. END
  151. END;
  152. RETURN f
  153. END ThisResFile;
  154. PROCEDURE Read2 (VAR x: INTEGER);
  155. VAR b: BYTE;
  156. BEGIN
  157. R.ReadByte(b); x := b MOD 256;
  158. R.ReadByte(b); x := x + 100H * (b MOD 256)
  159. END Read2;
  160. PROCEDURE Read4 (VAR x: INTEGER);
  161. VAR b: BYTE;
  162. BEGIN
  163. R.ReadByte(b); x := b MOD 256;
  164. R.ReadByte(b); x := x + 100H * (b MOD 256);
  165. R.ReadByte(b); x := x + 10000H * (b MOD 256);
  166. R.ReadByte(b); x := x + 1000000H * b
  167. END Read4;
  168. PROCEDURE ReadName (VAR name: ARRAY OF SHORTCHAR);
  169. VAR i: INTEGER; b: BYTE;
  170. BEGIN i := 0;
  171. REPEAT
  172. R.ReadByte(b); name[i] := SHORT(CHR(b)); INC(i)
  173. UNTIL b = 0
  174. END ReadName;
  175. PROCEDURE RNum (VAR i: INTEGER);
  176. VAR b: BYTE; s, y: INTEGER;
  177. BEGIN
  178. s := 0; y := 0; R.ReadByte(b);
  179. WHILE b < 0 DO INC(y, ASH(b + 128, s)); INC(s, 7); R.ReadByte(b) END;
  180. i := ASH((b + 64) MOD 128 - 64, s) + y
  181. END RNum;
  182. PROCEDURE WriteCh (ch: SHORTCHAR);
  183. BEGIN
  184. Ro.WriteByte(SHORT(ORD(ch)))
  185. END WriteCh;
  186. PROCEDURE Write2 (x: INTEGER);
  187. BEGIN
  188. Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
  189. Ro.WriteByte(SHORT(SHORT(x MOD 256)))
  190. END Write2;
  191. PROCEDURE Write4 (x: INTEGER);
  192. BEGIN
  193. Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
  194. Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
  195. Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
  196. Ro.WriteByte(SHORT(SHORT(x MOD 256)))
  197. END Write4;
  198. PROCEDURE WriteName (s: ARRAY OF SHORTCHAR; len: SHORTINT);
  199. VAR i: SHORTINT;
  200. BEGIN i := 0;
  201. WHILE s[i] # 0X DO Ro.WriteByte(SHORT(ORD(s[i]))); INC(i) END;
  202. WHILE i < len DO Ro.WriteByte(0); INC(i) END
  203. END WriteName;
  204. PROCEDURE Reloc (a: INTEGER);
  205. VAR p: POINTER TO ARRAY OF INTEGER; i: INTEGER;
  206. BEGIN
  207. IF noffixup >= LEN(fixups) THEN
  208. NEW(p, 2 * LEN(fixups));
  209. i := 0; WHILE i < LEN(fixups) DO p[i] := fixups[i]; INC(i) END;
  210. fixups := p
  211. END;
  212. fixups[noffixup] := a; INC(noffixup)
  213. (*
  214. ELSE
  215. IF ~error THEN W.WriteSString(" too many fixups") END;
  216. error := TRUE
  217. END
  218. *)
  219. END Reloc;
  220. PROCEDURE Put (mod: Module; a, x: INTEGER);
  221. BEGIN
  222. mod.data[a] := SHORT(SHORT(x)); INC(a); x := x DIV 256;
  223. mod.data[a] := SHORT(SHORT(x)); INC(a); x := x DIV 256;
  224. mod.data[a] := SHORT(SHORT(x)); INC(a); x := x DIV 256;
  225. mod.data[a] := SHORT(SHORT(x))
  226. END Put;
  227. PROCEDURE Get (mod: Module; a: INTEGER; VAR x: INTEGER);
  228. BEGIN
  229. x := ((mod.data[a + 3] * 256 +
  230. (mod.data[a + 2] MOD 256)) * 256 +
  231. (mod.data[a + 1] MOD 256)) * 256 +
  232. (mod.data[a] MOD 256)
  233. END Get;
  234. PROCEDURE GenName (VAR from, to: ARRAY OF SHORTCHAR; ext: ARRAY OF SHORTCHAR);
  235. VAR i, j: INTEGER;
  236. BEGIN
  237. i := 0;
  238. WHILE from[i] # 0X DO to[i] := from[i]; INC(i) END;
  239. IF ext # "" THEN
  240. to[i] := "."; INC(i); j := 0;
  241. WHILE ext[j] # 0X DO to[i] := ext[j]; INC(i); INC(j) END
  242. END;
  243. to[i] := 0X
  244. END GenName;
  245. PROCEDURE Fixup0 (link, adr: INTEGER);
  246. VAR offset, linkadr, t, n, x: INTEGER;
  247. BEGIN
  248. WHILE link # 0 DO
  249. RNum(offset);
  250. WHILE link # 0 DO
  251. IF link > 0 THEN
  252. n := (code[link] MOD 256) + (code[link+1] MOD 256) * 256 + code[link+2] * 65536;
  253. t := code[link+3]; linkadr := CodeBase + impg.ca + link
  254. ELSE
  255. n := (impg.data[-link] MOD 256) + (impg.data[-link+1] MOD 256) * 256 + impg.data[-link+2] * 65536;
  256. t := impg.data[-link+3]; linkadr := ConBase + impg.ma - link
  257. END;
  258. IF t = absolute THEN x := adr + offset
  259. ELSIF t = relative THEN x := adr + offset - linkadr - 4
  260. ELSIF t = copy THEN Get(impd, adr + offset - ConBase - impd.ma, x)
  261. ELSIF t = table THEN x := adr + n; n := link + 4
  262. ELSIF t = tableend THEN x := adr + n; n := 0
  263. ELSE HALT(99)
  264. END;
  265. IF link > 0 THEN
  266. code[link] := SHORT(SHORT(x));
  267. code[link+1] := SHORT(SHORT(x DIV 100H));
  268. code[link+2] := SHORT(SHORT(x DIV 10000H));
  269. code[link+3] := SHORT(SHORT(x DIV 1000000H))
  270. ELSE
  271. link := -link;
  272. impg.data[link] := SHORT(SHORT(x));
  273. impg.data[link+1] := SHORT(SHORT(x DIV 100H));
  274. impg.data[link+2] := SHORT(SHORT(x DIV 10000H));
  275. impg.data[link+3] := SHORT(SHORT(x DIV 1000000H))
  276. END;
  277. IF (t # relative) & ((t # copy) OR (x DIV 65536 # 0)) THEN Reloc(linkadr) END;
  278. link := n
  279. END;
  280. RNum(link)
  281. END
  282. END Fixup0;
  283. PROCEDURE Fixup (adr: INTEGER);
  284. VAR link: INTEGER;
  285. BEGIN
  286. RNum(link); Fixup0(link, adr)
  287. END Fixup;
  288. PROCEDURE CheckDllImports (mod: Module);
  289. VAR i, x, y: INTEGER; name: Name; imp: Module; exp: Export;
  290. PROCEDURE SkipLink;
  291. VAR a: INTEGER;
  292. BEGIN
  293. RNum(a);
  294. WHILE a # 0 DO RNum(a); RNum(a) END
  295. END SkipLink;
  296. BEGIN
  297. R := mod.file.NewReader(R);
  298. R.SetPos(mod.hs + mod.ms + mod.ds + mod.cs);
  299. SkipLink; SkipLink; SkipLink; SkipLink; SkipLink; SkipLink; i := 0;
  300. WHILE i < mod.ni DO
  301. imp := mod.imp[i];
  302. IF imp # NIL THEN
  303. RNum(x);
  304. WHILE x # 0 DO
  305. ReadName(name); RNum(y);
  306. IF x = mVar THEN SkipLink;
  307. IF imp.dll THEN
  308. WriteString("variable (");
  309. WriteString(imp.name); WriteChar(".");
  310. WriteSString(name);
  311. WriteString(") imported from DLL in ");
  312. WriteString(mod.name);
  313. WriteLn; FlushW; error := TRUE;
  314. RETURN
  315. END
  316. ELSIF x = mTyp THEN RNum(y);
  317. IF imp.dll THEN
  318. RNum(y);
  319. IF y # 0 THEN
  320. WriteString("type descriptor (");
  321. WriteString(imp.name); WriteChar(".");
  322. WriteSString(name);
  323. WriteString(") imported from DLL in ");
  324. WriteString(mod.name);
  325. WriteLn; FlushW; error := TRUE;
  326. RETURN
  327. END
  328. ELSE SkipLink
  329. END
  330. ELSIF x = mProc THEN
  331. IF imp.dll THEN
  332. SkipLink; exp := imp.exp;
  333. WHILE (exp # NIL) & (exp.name # name) DO exp := exp.next END;
  334. IF exp = NIL THEN
  335. NEW(exp); exp.name := name$;
  336. exp.next := imp.exp; imp.exp := exp; INC(DllSize, 6)
  337. END
  338. END
  339. END;
  340. RNum(x)
  341. END
  342. END;
  343. INC(i)
  344. END
  345. END CheckDllImports;
  346. PROCEDURE ReadHeaders;
  347. VAR mod, im, t: Module; x, i: INTEGER; impdll: BOOLEAN; exp: Export; name: Name;
  348. BEGIN
  349. mod := modList; modList := NIL; numMod := 0;
  350. WHILE mod # NIL DO (* reverse mod list & count modules *)
  351. IF ~mod.dll THEN INC(numMod) END;
  352. t := mod; mod := t.next; t.next := modList; modList := t
  353. END;
  354. IF isStatic THEN
  355. IF isDll THEN
  356. (* push ebx; cmp [12, esp], 1; jne L1; mov ebx, modlist; { call body; } jp L2 *)
  357. (* L1: cmp [12, esp], 0; jne L2; { call term; } *)
  358. (* L2: pop ebx; mov aex,1; ret 12 *)
  359. CodeSize := 42 + 10 * numMod
  360. ELSE
  361. (* push ebx; push ebx; push ebx; mov ebx, modlist; { call body; } { call term; } *)
  362. (* pop ebx; pop ebx; pop ebx; ret *)
  363. CodeSize := 12 + 10 * numMod
  364. END
  365. ELSE
  366. IF isDll THEN
  367. (* push ebx; cmp [12, esp], 1; jne L1; mov ebx, modlist; call main; jp L2 *)
  368. (* L1: cmp [12, esp], 0; jne L2; call mainTerm; *)
  369. (* L2: pop ebx; mov aex,1; ret 12 *)
  370. CodeSize := 41
  371. ELSE
  372. (* mov ebx, modlist; jmp main *)
  373. CodeSize := 10
  374. END
  375. END;
  376. (*
  377. IF isDll THEN
  378. CodeSize := 24 (* push ebx, esi, edi; mov bx, modlist; call main; pop edi, esi, ebx; mov aex,1; ret 12 *)
  379. ELSE
  380. CodeSize := 10 (* mov bx, modlist; jmp main *)
  381. END
  382. *)
  383. DataSize := 0; ConSize := 0;
  384. ImpSize := 0; ImpHSize := 0; ExpSize := 0;
  385. RelocSize := 0; DllSize := 0; noffixup := 0; maxCode := 0; numImp := 0; numExp := 0;
  386. mod := modList;
  387. WHILE mod # NIL DO
  388. IF ~mod.dll THEN
  389. mod.file := ThisFile(mod.name);
  390. IF mod.file # NIL THEN
  391. R := mod.file.NewReader(R); R.SetPos(0); Read4(x);
  392. IF x = 6F4F4346H THEN
  393. Read4(x);
  394. Read4(mod.hs); Read4(mod.ms); Read4(mod.ds); Read4(mod.cs);
  395. Read4(mod.vs); RNum(mod.ni); ReadName(name); impdll := FALSE;
  396. IF mod.ni > 0 THEN
  397. NEW(mod.imp, mod.ni); x := 0;
  398. WHILE x < mod.ni DO
  399. ReadName(name);
  400. IF name = "$$" THEN
  401. IF (mod # kernel) & (kernel # NIL) THEN
  402. mod.imp[x] := kernel
  403. ELSE
  404. WriteSString("no kernel"); WriteLn;
  405. FlushW; error := TRUE
  406. END
  407. ELSIF name[0] = "$" THEN
  408. i := 1;
  409. WHILE name[i] # 0X DO name[i-1] := name[i]; INC(i) END;
  410. name[i-1] := 0X; impdll := TRUE; im := modList;
  411. WHILE (im # mod) & (im.name # name) DO im := im.next END;
  412. IF (im = NIL) OR ~im.dll THEN
  413. NEW(im); im.next := modList; modList := im;
  414. im.name := name$;
  415. im.dll := TRUE
  416. END;
  417. mod.imp[x] := im;
  418. ELSE
  419. im := modList;
  420. WHILE (im # mod) & (im.name # name) DO im := im.next END;
  421. IF im # mod THEN
  422. mod.imp[x] := im;
  423. ELSE
  424. WriteSString(name);
  425. WriteString(" not present (imported in ");
  426. WriteString(mod.name); WriteChar(")");
  427. WriteLn; FlushW; error := TRUE
  428. END
  429. END;
  430. INC(x)
  431. END
  432. END;
  433. IF impdll & ~error THEN CheckDllImports(mod) END;
  434. mod.ma := ConSize; INC(ConSize, mod.ms + mod.ds);
  435. mod.va := DataSize; INC(DataSize, mod.vs);
  436. mod.ca := CodeSize; INC(CodeSize, mod.cs);
  437. IF mod.cs > maxCode THEN maxCode := mod.cs END
  438. ELSE
  439. WriteString(mod.name); WriteString(": wrong file type");
  440. WriteLn; FlushW; error := TRUE
  441. END;
  442. mod.file.Close; mod.file := NIL
  443. ELSE
  444. WriteString(mod.name); WriteString(" not found");
  445. WriteLn; FlushW; error := TRUE
  446. END;
  447. last := mod
  448. END;
  449. mod := mod.next
  450. END;
  451. IF ~isStatic & (main = NIL) THEN
  452. WriteSString("no main module specified"); WriteLn;
  453. FlushW; error := TRUE
  454. END;
  455. (* calculate rva's *)
  456. IF DataSize = 0 THEN DataSize := 1 END;
  457. CodeRva := ObjAlign;
  458. DataRva := CodeRva + (CodeSize + DllSize + (ObjAlign - 1)) DIV ObjAlign * ObjAlign;
  459. ConRva := DataRva + (DataSize + (ObjAlign - 1)) DIV ObjAlign * ObjAlign;
  460. RsrcRva := ConRva + (ConSize + (ObjAlign - 1)) DIV ObjAlign * ObjAlign;
  461. CodeBase := ImageBase + CodeRva;
  462. DataBase := ImageBase + DataRva;
  463. ConBase := ImageBase + ConRva;
  464. (* write dll export adresses *)
  465. mod := modList; x := 0;
  466. WHILE mod # NIL DO
  467. IF mod.dll THEN
  468. exp := mod.exp; INC(ImpSize, 20);
  469. WHILE exp # NIL DO exp.adr := x; INC(x, 6); exp := exp.next END
  470. END;
  471. mod := mod.next
  472. END;
  473. ASSERT(x = DllSize); INC(ImpSize, 20); (* sentinel *)
  474. END ReadHeaders;
  475. PROCEDURE MenuSize (r: Resource): INTEGER;
  476. VAR s, i: INTEGER;
  477. BEGIN
  478. s := 0;
  479. WHILE r # NIL DO
  480. INC(s, 2);
  481. IF r.local = NIL THEN INC(s, 2) END;
  482. i := 0; WHILE r.name[i] # 0X DO INC(s, 2); INC(i) END;
  483. INC(s, 2);
  484. s := s + MenuSize(r.local);
  485. r := r.next
  486. END;
  487. RETURN s
  488. END MenuSize;
  489. PROCEDURE PrepResources;
  490. VAR res, r, s: Resource; n, i, j, t, x: INTEGER; loc: Files.Locator;
  491. BEGIN
  492. r := resList;
  493. WHILE r # NIL DO
  494. IF r.lid = 0 THEN r.lid := 1033 END;
  495. IF r.name = "MENU" THEN
  496. r.typ := 4; r.size := 4 + MenuSize(r.local);
  497. ELSIF r.name = "ACCELERATOR" THEN
  498. r.typ := 9; r.size := 0; s := r.local;
  499. WHILE s # NIL DO INC(r.size, 8); s := s.next END;
  500. ELSE
  501. r.file := ThisResFile(r.name);
  502. IF r.file # NIL THEN
  503. IF r.typ = -1 THEN (* typelib *)
  504. r.typ := 0; r.size := r.file.Length(); r.pos := 0; rsrcName := "TYPELIB"
  505. ELSE
  506. R := r.file.NewReader(R); R.SetPos(0); Read2(n);
  507. IF n = 4D42H THEN (* bitmap *)
  508. Read4(n); r.typ := 2; r.size := n - 14; r.pos := 14;
  509. ELSE
  510. Read2(x);
  511. IF x = 1 THEN (* icon *)
  512. Read2(n); r.typ := 14; r.size := 6 + 14 * n; r.pos := 0; i := 0;
  513. WHILE i < n DO
  514. NEW(s); s.typ := 3; s.id := 10 * r.id + i; s.lid := r.lid; s.name := r.name$;
  515. Read4(x); Read4(x); Read4(s.size); Read2(s.pos); Read2(x);
  516. s.next := resList; resList := s;
  517. INC(i)
  518. END
  519. ELSIF x = 2 THEN (* cursor *)
  520. Read2(n); r.typ := 12; r.size := 6 + 14 * n; r.pos := 0; i := 0;
  521. WHILE i < n DO
  522. NEW(s); s.typ := 1; s.id := 10 * r.id + i; s.lid := r.lid; s.name := r.name$;
  523. Read4(x); Read2(s.x); Read2(s.y); Read4(s.size); INC(s.size, 4); Read2(s.pos); Read2(x);
  524. s.next := resList; resList := s;
  525. INC(i)
  526. END
  527. ELSE
  528. Read4(n);
  529. IF (x = 0) & (n = 20H) THEN (* resource file *)
  530. Read4(n); Read4(n); Read4(n); Read4(n); Read4(n); Read4(n); (* 32 bit marker *)
  531. Read4(r.size); Read4(n); Read2(i);
  532. IF i = 0FFFFH THEN
  533. Read2(j);
  534. IF (j >= 4) & ((j <= 11) OR (j = 16)) THEN
  535. r.typ := j; r.pos := n + 32;
  536. ELSE
  537. WriteString(r.name); WriteString(": invalid type"); WriteLn;
  538. FlushW; error := TRUE
  539. END
  540. ELSE
  541. j := 0;
  542. WHILE i # 0 DO rsrcName[j] := CHR(i); INC(j); Read2(i) END;
  543. rsrcName[j] := 0X;
  544. r.typ := 0; r.pos := n + 32
  545. END
  546. ELSE
  547. WriteString(r.name); WriteString(": unknown type"); WriteLn;
  548. FlushW; error := TRUE
  549. END
  550. END
  551. END
  552. END;
  553. r.file.Close; r.file := NIL
  554. ELSE
  555. WriteString(r.name); WriteString(" not found"); WriteLn;
  556. FlushW; error := TRUE
  557. END
  558. END;
  559. r := r.next
  560. END;
  561. res := resList; resList := NIL; (* sort resources *)
  562. WHILE res # NIL DO
  563. r := res; res := res.next;
  564. IF (resList = NIL) OR (r.typ < resList.typ) OR (r.typ = resList.typ) & ((r.id < resList.id) OR (r.id = resList.id) & (r.lid < resList.lid))
  565. THEN
  566. r.next := resList; resList := r
  567. ELSE
  568. s := resList;
  569. WHILE (s.next # NIL) & (r.typ >= s.next.typ)
  570. & ((r.typ # s.next.typ) OR (r.id >= s.next.id) & ((r.id # s.next.id) OR (r.lid >= s.next.lid))) DO s := s.next END;
  571. r.next := s.next; s.next := r
  572. END
  573. END;
  574. r := resList; numType := 0; resHSize := 16; t := 0; n := 0; (* get resource size *)
  575. WHILE t < LEN(numId) DO numId[t] := 0; INC(t) END;
  576. WHILE r # NIL DO
  577. INC(numType); INC(resHSize, 24); t := r.typ;
  578. WHILE (r # NIL) & (r.typ = t) DO
  579. INC(numId[t]); INC(resHSize, 24); i := r.id;
  580. WHILE (r # NIL) & (r.typ = t) & (r.id = i) DO
  581. INC(resHSize, 24); INC(n, (r.size + 3) DIV 4 * 4); r := r.next
  582. END
  583. END
  584. END;
  585. IF numId[0] > 0 THEN INC(n, (LEN(rsrcName$) + 1) * 2) END;
  586. RsrcSize := resHSize + n;
  587. ImpRva := RsrcRva + (RsrcSize + (ObjAlign - 1)) DIV ObjAlign * ObjAlign
  588. END PrepResources;
  589. PROCEDURE WriteHeader(VAR name: Files.Name);
  590. BEGIN
  591. Out := Files.dir.New(Files.dir.This(""), Files.ask); Ro := Out.NewWriter(Ro); Ro.SetPos(0);
  592. (* DOS header *)
  593. Write4(905A4DH); Write4(3); Write4(4); Write4(0FFFFH);
  594. Write4(0B8H); Write4(0); Write4(40H); Write4(0);
  595. Write4(0); Write4(0); Write4(0); Write4(0);
  596. Write4(0); Write4(0); Write4(0); Write4(80H);
  597. Write4(0EBA1F0EH); Write4(0CD09B400H); Write4(4C01B821H); Write2(21CDH);
  598. WriteName("This program cannot be run in DOS mode.", 39);
  599. WriteCh(0DX); WriteCh(0DX); WriteCh(0AX);
  600. Write4(24H); Write4(0);
  601. (* Win32 header *)
  602. WriteName("PE", 4); (* signature bytes *)
  603. Write2(014CH); (* cpu type (386) *)
  604. IF isDll THEN
  605. Write2(7); (* 7 objects *)
  606. ELSE
  607. Write2(6); (* 6 objects *)
  608. END;
  609. Write4(timeStamp); (* time/date *)
  610. Write4(0); Write4(0);
  611. Write2(0E0H); (* NT header size *)
  612. IF isDll THEN
  613. Write2(0A38EH); (* library image flags *)
  614. ELSE
  615. Write2(838EH); (* program image flags *)
  616. END;
  617. Write2(10BH); (* magic (normal ececutable file) *)
  618. Write2(0301H); (* linker version !!! *)
  619. Write4(CodeSize); (* code size *)
  620. Write4(ConSize); (* initialized data size *)
  621. Write4(DataSize); (* uninitialized data size *)
  622. entryPos := Ro.Pos();
  623. Write4(0); (* entry point *) (* !!! *)
  624. Write4(CodeRva); (* base of code *)
  625. Write4(ConRva); (* base of data *)
  626. Write4(400000H); (* image base *)
  627. Write4(ObjAlign); (* object align *)
  628. Write4(FileAlign); (* file align *)
  629. Write4(3); (* OS version *)
  630. Write4(4); (* user version *)
  631. Write4(4); (* subsys version *) (* mf 14.3.04: value changed from 0A0003H to 4. Corrects menubar pixel bug on Windows XP *)
  632. Write4(0);
  633. isPos := Ro.Pos();
  634. Write4(0); (* image size *) (* !!! *)
  635. Write4(HeaderSize); (* header size !!! *)
  636. Write4(0); (* checksum *)
  637. IF comLine THEN
  638. Write2(3) (* dos subsystem *)
  639. ELSE
  640. Write2(2) (* gui subsystem *)
  641. END;
  642. Write2(0); (* dll flags *)
  643. Write4(200000H); (* stack reserve size *)
  644. Write4(10000H); (* stack commit size *)
  645. IF isDll THEN
  646. Write4(00100000H); (* heap reserve size *)
  647. ELSE
  648. Write4(00400000H); (* heap reserve size *)
  649. END;
  650. Write4(10000H); (* heap commit size *)
  651. Write4(0);
  652. Write4(16); (* num of rva/sizes *)
  653. hexpPos := Ro.Pos();
  654. Write4(0); Write4(0); (* export table *)
  655. himpPos := Ro.Pos();
  656. Write4(0); Write4(0); (* import table *) (* !!! *)
  657. hrsrcPos := Ro.Pos();
  658. Write4(0); Write4(0); (* resource table *) (* !!! *)
  659. Write4(0); Write4(0); (* exception table *)
  660. Write4(0); Write4(0); (* security table *)
  661. fixPos := Ro.Pos();
  662. Write4(0); Write4(0); (* fixup table *) (* !!! *)
  663. Write4(0); Write4(0); (* debug table *)
  664. Write4(0); Write4(0); (* image description *)
  665. Write4(0); Write4(0); (* machine specific *)
  666. Write4(0); Write4(0); (* thread local storage *)
  667. Write4(0); Write4(0); (* ??? *)
  668. Write4(0); Write4(0); (* ??? *)
  669. Write4(0); Write4(0); (* ??? *)
  670. Write4(0); Write4(0); (* ??? *)
  671. Write4(0); Write4(0); (* ??? *)
  672. Write4(0); Write4(0); (* ??? *)
  673. (* object directory *)
  674. WriteName(".text", 8); (* code object *)
  675. Write4(0); (* object size (always 0) *)
  676. codePos := Ro.Pos();
  677. Write4(0); (* object rva *)
  678. Write4(0); (* physical size *)
  679. Write4(0); (* physical offset *)
  680. Write4(0); Write4(0); Write4(0);
  681. Write4(60000020H); (* flags: code, exec, read *)
  682. WriteName(".var", 8); (* variable object *)
  683. Write4(0); (* object size (always 0) *)
  684. dataPos := Ro.Pos();
  685. Write4(0); (* object rva *)
  686. Write4(0); (* physical size *)
  687. Write4(0); (* physical offset *) (* zero! (noinit) *)
  688. Write4(0); Write4(0); Write4(0);
  689. Write4(0C0000080H); (* flags: noinit, read, write *)
  690. WriteName(".data", 8); (* constant object *)
  691. Write4(0); (* object size (always 0) *)
  692. conPos := Ro.Pos();
  693. Write4(0); (* object rva *)
  694. Write4(0); (* physical size *)
  695. Write4(0); (* physical offset *)
  696. Write4(0); Write4(0); Write4(0);
  697. Write4(0C0000040H); (* flags: data, read, write *)
  698. WriteName(".rsrc", 8); (* resource object *)
  699. Write4(0); (* object size (always 0) *)
  700. rsrcPos := Ro.Pos();
  701. Write4(0); (* object rva *)
  702. Write4(0); (* physical size *)
  703. Write4(0); (* physical offset *)
  704. Write4(0); Write4(0); Write4(0);
  705. Write4(0C0000040H); (* flags: data, read, write *)
  706. WriteName(".idata", 8); (* import object *)
  707. Write4(0); (* object size (always 0) *)
  708. impPos := Ro.Pos();
  709. Write4(0); (* object rva *)
  710. Write4(0); (* physical size *)
  711. Write4(0); (* physical offset *)
  712. Write4(0); Write4(0); Write4(0);
  713. Write4(0C0000040H); (* flags: data, read, write *)
  714. IF isDll THEN
  715. WriteName(".edata", 8); (* export object *)
  716. Write4(0); (* object size (always 0) *)
  717. expPos := Ro.Pos();
  718. Write4(0); (* object rva *)
  719. Write4(0); (* physical size *)
  720. Write4(0); (* physical offset *)
  721. Write4(0); Write4(0); Write4(0);
  722. Write4(0C0000040H); (* flags: data, read, write *)
  723. END;
  724. WriteName(".reloc", 8); (* relocation object *)
  725. Write4(0); (* object size (always 0) *)
  726. relPos := Ro.Pos();
  727. Write4(0); (* object rva *)
  728. Write4(0); (* physical size *)
  729. Write4(0); (* physical offset *)
  730. Write4(0); Write4(0); Write4(0);
  731. Write4(42000040H); (* flags: data, read, ? *)
  732. END WriteHeader;
  733. PROCEDURE SearchObj (mod: Module; VAR name: ARRAY OF SHORTCHAR; m, fp, opt: INTEGER; VAR adr: INTEGER);
  734. VAR dir, len, ntab, f, id, l, r, p, n, i, j: INTEGER; nch, och: SHORTCHAR;
  735. BEGIN
  736. Get(mod, mod.ms + modExports, dir); DEC(dir, ConBase + mod.ma); Get(mod, dir, len); INC(dir, 4);
  737. Get(mod, mod.ms + modNames, ntab); DEC(ntab, ConBase + mod.ma);
  738. IF name # "" THEN
  739. l := 0; r := len;
  740. WHILE l < r DO (* binary search *)
  741. n := (l + r) DIV 2; p := dir + n * 16;
  742. Get(mod, p + 8, id);
  743. i := 0; j := ntab + id DIV 256; nch := name[0]; och := SHORT(CHR(mod.data[j]));
  744. WHILE (nch = och) & (nch # 0X) DO INC(i); INC(j); nch := name[i]; och := SHORT(CHR(mod.data[j])) END;
  745. IF och = nch THEN
  746. IF id MOD 16 = m THEN Get(mod, p, f);
  747. IF m = mTyp THEN
  748. IF ODD(opt) THEN Get(mod, p + 4, f) END;
  749. IF (opt > 1) & (id DIV 16 MOD 16 # mExported) THEN
  750. WriteString(mod.name); WriteChar("."); WriteSString(name);
  751. WriteString(" imported from "); WriteString(impg.name);
  752. WriteString(" has wrong visibility"); WriteLn; error := TRUE
  753. END;
  754. Get(mod, p + 12, adr)
  755. ELSIF m = mVar THEN
  756. Get(mod, p + 4, adr); INC(adr, DataBase + mod.va)
  757. ELSIF m = mProc THEN
  758. Get(mod, p + 4, adr); INC(adr, CodeBase + mod.ca)
  759. END;
  760. IF f # fp THEN
  761. WriteString(mod.name); WriteChar("."); WriteSString(name);
  762. WriteString(" imported from "); WriteString(impg.name);
  763. WriteString(" has wrong fprint"); WriteLn; error := TRUE
  764. END
  765. ELSE
  766. WriteString(mod.name); WriteChar("."); WriteSString(name);
  767. WriteString(" imported from "); WriteString(impg.name);
  768. WriteString(" has wrong class"); WriteLn; error := TRUE
  769. END;
  770. RETURN
  771. END;
  772. IF och < nch THEN l := n + 1 ELSE r := n END
  773. END;
  774. WriteString(mod.name); WriteChar("."); WriteSString(name);
  775. WriteString(" not found (imported from "); WriteString(impg.name);
  776. WriteChar(")"); WriteLn; error := TRUE
  777. ELSE (* anonymous type *)
  778. WHILE len > 0 DO
  779. Get(mod, dir + 4, f); Get(mod, dir + 8, id);
  780. IF (f = fp) & (id MOD 16 = mTyp) & (id DIV 256 = 0) THEN
  781. Get(mod, dir + 12, adr); RETURN
  782. END;
  783. DEC(len); INC(dir, 16)
  784. END;
  785. WriteString("anonymous type in "); WriteString(mod.name);
  786. WriteString(" not found"); WriteLn; error := TRUE
  787. END
  788. END SearchObj;
  789. PROCEDURE CollectExports (mod: Module);
  790. VAR dir, len, ntab, id, i, j, n: INTEGER; e, exp: Export;
  791. BEGIN
  792. Get(mod, mod.ms + modExports, dir); DEC(dir, ConBase + mod.ma); Get(mod, dir, len); INC(dir, 4);
  793. Get(mod, mod.ms + modNames, ntab); DEC(ntab, ConBase + mod.ma); n := 0;
  794. WHILE n < len DO
  795. Get(mod, dir + 8, id);
  796. IF (id DIV 16 MOD 16 # mInternal) & ((id MOD 16 = mProc) OR (id MOD 16 = mVar))THEN (* exported procedure & var *)
  797. NEW(exp);
  798. i := 0; j := ntab + id DIV 256;
  799. WHILE mod.data[j] # 0 DO exp.name[i] := SHORT(CHR(mod.data[j])); INC(i); INC(j) END;
  800. exp.name[i] := 0X;
  801. Get(mod, dir + 4, exp.adr);
  802. IF id MOD 16 = mProc THEN INC(exp.adr, CodeRva + mod.ca)
  803. ELSE ASSERT(id MOD 16 = mVar); INC(exp.adr, DataRva + mod.va)
  804. END;
  805. IF (firstExp = NIL) OR (exp.name < firstExp.name) THEN
  806. exp.next := firstExp; firstExp := exp;
  807. IF lastExp = NIL THEN lastExp := exp END
  808. ELSE
  809. e := firstExp;
  810. WHILE (e.next # NIL) & (exp.name > e.next.name) DO e := e.next END;
  811. exp.next := e.next; e.next := exp;
  812. IF lastExp = e THEN lastExp := exp END
  813. END;
  814. INC(numExp);
  815. END;
  816. INC(n); INC(dir, 16)
  817. END
  818. END CollectExports;
  819. PROCEDURE WriteTermCode (m: Module; i: INTEGER);
  820. VAR x: INTEGER;
  821. BEGIN
  822. IF m # NIL THEN
  823. IF m.dll THEN WriteTermCode(m.next, i)
  824. ELSE
  825. IF isStatic THEN WriteTermCode(m.next, i + 1) END;
  826. Get(m, m.ms + modTerm, x); (* terminator address in mod desc*)
  827. IF x = 0 THEN
  828. WriteCh(005X); Write4(0) (* add EAX, 0 (nop) *)
  829. ELSE
  830. WriteCh(0E8X); Write4(x - lastTerm + 5 * i - CodeBase) (* call term *)
  831. END
  832. END
  833. END
  834. END WriteTermCode;
  835. PROCEDURE WriteCode;
  836. VAR mod, m: Module; i, x, a, fp, opt: INTEGER; exp: Export; name: Name;
  837. BEGIN
  838. IF isStatic THEN
  839. WriteCh(053X); (* push ebx *)
  840. a := 1;
  841. IF isDll THEN
  842. WriteCh(083X); WriteCh(07CX); WriteCh(024X); WriteCh(00CX); WriteCh(001X); (* cmp [12, esp], 1 *)
  843. WriteCh(00FX); WriteCh(085X); Write4(10 + 5 * numMod); (* jne L1 *)
  844. INC(a, 11)
  845. ELSE
  846. WriteCh(053X); WriteCh(053X); (* push ebx; push ebx *)
  847. INC(a, 2)
  848. END;
  849. WriteCh(0BBX); Write4(ConBase + last.ma + last.ms); Reloc(CodeBase + a + 1); (* mov bx, modlist *)
  850. INC(a, 5); m := modList;
  851. WHILE m # NIL DO
  852. IF ~m.dll THEN
  853. WriteCh(0E8X); INC(a, 5); Write4(m.ca - a) (* call body *)
  854. END;
  855. m := m.next
  856. END;
  857. IF isDll THEN
  858. WriteCh(0E9X); Write4(11 + 5 * numMod); (* jp L2 *)
  859. WriteCh(083X); WriteCh(07CX); WriteCh(024X); WriteCh(00CX); WriteCh(000X); (* L1: cmp [12, esp], 0 *)
  860. WriteCh(00FX); WriteCh(085X); Write4(5 * numMod); (* jne L2 *)
  861. INC(a, 16)
  862. END;
  863. termPos := Ro.Pos(); i := 0;
  864. WHILE i < numMod DO (* nop for call terminator *)
  865. WriteCh(02DX); Write4(0); (* sub EAX, 0 *)
  866. INC(i); INC(a, 5)
  867. END;
  868. lastTerm := a;
  869. WriteCh(05BX); (* L2: pop ebx *)
  870. IF isDll THEN
  871. WriteCh(0B8X); Write4(1); (* mov eax,1 *)
  872. WriteCh(0C2X); Write2(12) (* ret 12 *)
  873. ELSE
  874. WriteCh(05BX); WriteCh(05BX); (* pop ebx; pop ebx *)
  875. WriteCh(0C3X) (* ret *)
  876. END
  877. ELSIF isDll THEN
  878. WriteCh(053X); (* push ebx *)
  879. WriteCh(083X); WriteCh(07CX); WriteCh(024X); WriteCh(00CX); WriteCh(001X); (* cmp [12, esp], 1 *)
  880. WriteCh(075X); WriteCh(SHORT(CHR(12))); (* jne L1 *)
  881. WriteCh(0BBX); Write4(ConBase + last.ma + last.ms); Reloc(CodeBase + 9); (* mov bx, modlist *)
  882. WriteCh(0E8X); Write4(main.ca - 18); (* call main *)
  883. WriteCh(0EBX); WriteCh(SHORT(CHR(12))); (* jp L2 *)
  884. WriteCh(083X); WriteCh(07CX); WriteCh(024X); WriteCh(00CX); WriteCh(000X); (* L1: cmp [12, esp], 0 *)
  885. WriteCh(075X); WriteCh(SHORT(CHR(5))); (* jne L2 *)
  886. termPos := Ro.Pos();
  887. WriteCh(02DX); Write4(0); (* sub EAX, 0 *) (* nop for call terminator *)
  888. lastTerm := 32;
  889. WriteCh(05BX); (* L2: pop ebx *)
  890. WriteCh(0B8X); Write4(1); (* mov eax,1 *)
  891. WriteCh(0C2X); Write2(12) (* ret 12 *)
  892. ELSE
  893. WriteCh(0BBX); Write4(ConBase + last.ma + last.ms); Reloc(CodeBase + 1); (* mov bx, modlist *)
  894. WriteCh(0E9X); Write4(main.ca - 10); (* jmp main *)
  895. END;
  896. NEW(code, maxCode);
  897. mod := modList;
  898. WHILE mod # NIL DO impg := mod; impd := mod;
  899. IF ~mod.dll THEN
  900. mod.file := ThisFile(mod.name);
  901. R := mod.file.NewReader(R); R.SetPos(mod.hs);
  902. NEW(mod.data, mod.ms + mod.ds);
  903. R.ReadBytes(mod.data^, 0, mod.ms + mod.ds);
  904. R.ReadBytes(code^, 0, mod.cs);
  905. RNum(x);
  906. IF x # 0 THEN
  907. IF (mod # kernel) & (kernel # NIL) THEN
  908. SearchObj(kernel, newRec, mProc, NewRecFP, -1, a); Fixup0(x, a)
  909. ELSE
  910. WriteSString("no kernel"); WriteLn;
  911. FlushW; error := TRUE; RETURN
  912. END
  913. END;
  914. RNum(x);
  915. IF x # 0 THEN
  916. IF (mod # kernel) & (kernel # NIL) THEN
  917. SearchObj(kernel, newArr, mProc, NewArrFP, -1, a); Fixup0(x, a)
  918. ELSE
  919. WriteSString("no kernel"); WriteLn;
  920. FlushW; error := TRUE; RETURN
  921. END
  922. END;
  923. Fixup(ConBase + mod.ma);
  924. Fixup(ConBase + mod.ma + mod.ms);
  925. Fixup(CodeBase + mod.ca);
  926. Fixup(DataBase + mod.va); i := 0;
  927. WHILE i < mod.ni DO
  928. m := mod.imp[i]; impd := m; RNum(x);
  929. WHILE x # 0 DO
  930. ReadName(name); RNum(fp); opt := 0;
  931. IF x = mTyp THEN RNum(opt) END;
  932. IF m.dll THEN
  933. IF x = mProc THEN exp := m.exp;
  934. WHILE exp.name # name DO exp := exp.next END;
  935. a := exp.adr + CodeBase + CodeSize
  936. END
  937. ELSE
  938. SearchObj(m, name, x, fp, opt, a)
  939. END;
  940. IF x # mConst THEN Fixup(a) END;
  941. RNum(x)
  942. END;
  943. IF ~m.dll THEN
  944. Get(mod, mod.ms + modImports, x); DEC(x, ConBase + mod.ma); INC(x, 4 * i);
  945. Put(mod, x, ConBase + m.ma + m.ms); (* imp ref *)
  946. Reloc(ConBase + mod.ma + x);
  947. Get(m, m.ms + modRefcnt, x); Put(m, m.ms + modRefcnt, x + 1) (* inc ref count *)
  948. END;
  949. INC(i)
  950. END;
  951. Ro.WriteBytes(code^, 0, mod.cs);
  952. IF mod.intf THEN CollectExports(mod) END;
  953. mod.file.Close; mod.file := NIL
  954. END;
  955. mod := mod.next
  956. END;
  957. (* dll links *)
  958. mod := modList; ImpHSize := ImpSize;
  959. WHILE mod # NIL DO
  960. IF mod.dll THEN
  961. exp := mod.exp;
  962. WHILE exp # NIL DO
  963. WriteCh(0FFX); WriteCh(25X); Write4(ImageBase + ImpRva + ImpSize); (* JMP indirect *)
  964. Reloc(CodeBase + CodeSize + exp.adr + 2);
  965. INC(ImpSize, 4); INC(numImp); exp := exp.next
  966. END;
  967. INC(ImpSize, 4); INC(numImp) (* sentinel *)
  968. END;
  969. mod := mod.next
  970. END
  971. END WriteCode;
  972. PROCEDURE WriteConst;
  973. VAR mod, last: Module; x: INTEGER;
  974. BEGIN
  975. mod := modList; last := NIL;
  976. WHILE mod # NIL DO
  977. IF ~mod.dll THEN
  978. IF last # NIL THEN
  979. Put(mod, mod.ms, ConBase + last.ma + last.ms); (* mod list *)
  980. Reloc(ConBase + mod.ma + mod.ms);
  981. END;
  982. Get(mod, mod.ms + modOpts, x);
  983. IF isStatic THEN INC(x, 10000H) END; (* set init bit (16) *)
  984. IF isDll THEN INC(x, 1000000H) END; (* set dll bit (24) *)
  985. Put(mod, mod.ms + modOpts, x);
  986. Ro.WriteBytes(mod.data^, 0, mod.ms + mod.ds);
  987. last := mod
  988. END;
  989. mod := mod.next
  990. END
  991. END WriteConst;
  992. PROCEDURE WriteResDir (n, i: INTEGER);
  993. BEGIN
  994. Write4(0); (* flags *)
  995. Write4(timeStamp);
  996. Write4(0); (* version *)
  997. Write2(n); (* name entries *)
  998. Write2(i); (* id entries *)
  999. END WriteResDir;
  1000. PROCEDURE WriteResDirEntry (id, adr: INTEGER; dir: BOOLEAN);
  1001. BEGIN
  1002. IF id = 0 THEN id := resHSize + 80000000H END; (* name Rva *)
  1003. Write4(id);
  1004. IF dir THEN Write4(adr + 80000000H) ELSE Write4(adr) END
  1005. END WriteResDirEntry;
  1006. PROCEDURE WriteMenu (res: Resource);
  1007. VAR f, i: INTEGER;
  1008. BEGIN
  1009. WHILE res # NIL DO
  1010. IF res.next = NIL THEN f := 80H ELSE f := 0 END;
  1011. IF 29 IN res.opts THEN INC(f, 1) END; (* = grayed *)
  1012. IF 13 IN res.opts THEN INC(f, 2) END; (* - inctive *)
  1013. IF 3 IN res.opts THEN INC(f, 4) END; (* # bitmap *)
  1014. IF 10 IN res.opts THEN INC(f, 8) END; (* * checked *)
  1015. IF 1 IN res.opts THEN INC(f, 20H) END; (* ! menubarbreak *)
  1016. IF 15 IN res.opts THEN INC(f, 40H) END; (* / menubreak *)
  1017. IF 31 IN res.opts THEN INC(f, 100H) END; (* ? ownerdraw *)
  1018. IF res.local # NIL THEN Write2(f + 10H) ELSE Write2(f); Write2(res.id) END;
  1019. i := 0; WHILE res.name[i] # 0X DO Write2(ORD(res.name[i])); INC(i) END;
  1020. Write2(0);
  1021. WriteMenu(res.local);
  1022. res := res.next
  1023. END
  1024. END WriteMenu;
  1025. PROCEDURE WriteResource;
  1026. VAR r, s: Resource; i, t, a, x, n, nlen, nsize: INTEGER;
  1027. BEGIN
  1028. IF numId[0] > 0 THEN WriteResDir(1, numType - 1); nlen := LEN(rsrcName$); nsize := (nlen + 1) * 2;
  1029. ELSE WriteResDir(0, numType)
  1030. END;
  1031. a := 16 + 8 * numType; t := 0;
  1032. WHILE t < LEN(numId) DO
  1033. IF numId[t] > 0 THEN WriteResDirEntry(t, a, TRUE); INC(a, 16 + 8 * numId[t]) END;
  1034. INC(t)
  1035. END;
  1036. r := resList; t := -1;
  1037. WHILE r # NIL DO
  1038. IF t # r.typ THEN t := r.typ; WriteResDir(0, numId[t]) END;
  1039. WriteResDirEntry(r.id, a, TRUE); INC(a, 16); i := r.id;
  1040. WHILE (r # NIL) & (r.typ = t) & (r.id = i) DO INC(a, 8); r := r.next END
  1041. END;
  1042. r := resList;
  1043. WHILE r # NIL DO
  1044. n := 0; s := r;
  1045. WHILE (s # NIL) & (s.typ = r.typ) & (s.id = r.id) DO INC(n); s := s.next END;
  1046. WriteResDir(0, n);
  1047. WHILE r # s DO WriteResDirEntry(r.lid, a, FALSE); INC(a, 16); r := r.next END
  1048. END;
  1049. ASSERT(a = resHSize);
  1050. IF numId[0] > 0 THEN INC(a, nsize) END; (* TYPELIB string *)
  1051. r := resList;
  1052. WHILE r # NIL DO
  1053. Write4(a + RsrcRva); INC(a, (r.size + 3) DIV 4 * 4);
  1054. Write4(r.size);
  1055. Write4(0); Write4(0);
  1056. r := r.next
  1057. END;
  1058. ASSERT(a = RsrcSize);
  1059. IF numId[0] > 0 THEN
  1060. Write2(nlen); i := 0;
  1061. WHILE rsrcName[i] # 0X DO Write2(ORD(rsrcName[i])); INC(i) END
  1062. END;
  1063. r := resList;
  1064. WHILE r # NIL DO
  1065. IF r.typ = 4 THEN (* menu *)
  1066. Write2(0); Write2(0);
  1067. WriteMenu(r.local);
  1068. WHILE Ro.Pos() MOD 4 # 0 DO WriteCh(0X) END
  1069. ELSIF r.typ = 9 THEN (* accelerator *)
  1070. s := r.local;
  1071. WHILE s # NIL DO
  1072. i := 0; a := 0;
  1073. IF 10 IN s.opts THEN INC(a, 4) END; (* * shift *)
  1074. IF 16 IN s.opts THEN INC(a, 8) END; (* ^ ctrl *)
  1075. IF 0 IN s.opts THEN INC(a, 16) END; (* @ alt *)
  1076. IF 13 IN s.opts THEN INC(a, 2) END; (* - noinv *)
  1077. IF s.next = NIL THEN INC(a, 80H) END;
  1078. IF (s.name[0] = "v") & (s.name[1] # 0X) THEN
  1079. s.name[0] := " "; Strings.StringToInt(s.name, x, n); INC(a, 1)
  1080. ELSE x := ORD(s.name[0])
  1081. END;
  1082. Write2(a); Write2(x); Write2(s.id); Write2(0); s := s.next
  1083. END
  1084. ELSE
  1085. r.file := ThisResFile(r.name);
  1086. IF r.file # NIL THEN
  1087. R := r.file.NewReader(R); R.SetPos(r.pos); i := 0;
  1088. IF r.typ = 12 THEN (* cursor group *)
  1089. Read4(x); Write4(x); Read2(n); Write2(n);
  1090. WHILE i < n DO
  1091. Read4(x); Write2(x MOD 256); Write2(x DIV 256 MOD 256 * 2);
  1092. Write2(1); Write2(1); Read4(x); (* ??? *)
  1093. Read4(x); Write4(x + 4); Read4(x); Write2(r.id * 10 + i); INC(i)
  1094. END;
  1095. IF ~ODD(n) THEN Write2(0) END
  1096. ELSIF r.typ = 14 THEN (* icon group *)
  1097. Read4(x); Write4(x); Read2(n); Write2(n);
  1098. WHILE i < n DO
  1099. Read2(x); Write2(x); Read2(x);
  1100. IF (13 IN r.opts) & (x = 16) THEN x := 4 END;
  1101. Write2(x);
  1102. a := x MOD 256; Read4(x); Write2(1);
  1103. IF a <= 2 THEN Write2(1)
  1104. ELSIF a <= 4 THEN Write2(2)
  1105. ELSIF a <= 16 THEN Write2(4)
  1106. ELSE Write2(8)
  1107. END;
  1108. Read4(x);
  1109. IF (13 IN r.opts) & (x = 744) THEN x := 440 END;
  1110. IF (13 IN r.opts) & (x = 296) THEN x := 184 END;
  1111. Write4(x); Read4(x); Write2(r.id * 10 + i); INC(i)
  1112. END;
  1113. IF ~ODD(n) THEN Write2(0) END
  1114. ELSE
  1115. IF r.typ = 1 THEN Write2(r.x); Write2(r.y); i := 4 END; (* cursor hot spot *)
  1116. WHILE i < r.size DO Read4(x); Write4(x); INC(i, 4) END
  1117. END;
  1118. r.file.Close; r.file := NIL
  1119. END
  1120. END;
  1121. r := r.next
  1122. END
  1123. END WriteResource;
  1124. PROCEDURE Insert(VAR name: ARRAY OF SHORTCHAR; VAR idx: INTEGER; hint: INTEGER);
  1125. VAR i: INTEGER;
  1126. BEGIN
  1127. IF hint >= 0 THEN
  1128. ntab[idx] := SHORT(CHR(hint)); INC(idx);
  1129. ntab[idx] := SHORT(CHR(hint DIV 256)); INC(idx);
  1130. END;
  1131. i := 0;
  1132. WHILE name[i] # 0X DO ntab[idx] := name[i]; INC(idx); INC(i) END;
  1133. IF (hint = -1) & ((ntab[idx-4] # ".") OR (CAP(ntab[idx-3]) # "D") OR (CAP(ntab[idx-2]) # "L") OR (CAP(ntab[idx-1]) # "L")) THEN
  1134. ntab[idx] := "."; INC(idx);
  1135. ntab[idx] := "d"; INC(idx);
  1136. ntab[idx] := "l"; INC(idx);
  1137. ntab[idx] := "l"; INC(idx);
  1138. END;
  1139. ntab[idx] := 0X; INC(idx);
  1140. IF ODD(idx) THEN ntab[idx] := 0X; INC(idx) END
  1141. END Insert;
  1142. PROCEDURE WriteImport;
  1143. VAR i, lt, at, nt, ai, ni: INTEGER; mod: Module; exp: Export; ss: ARRAY 256 OF SHORTCHAR;
  1144. BEGIN
  1145. IF numImp > 0 THEN NEW(atab, numImp) END;
  1146. IF numExp > numImp THEN i := numExp ELSE i := numImp END;
  1147. IF i > 0 THEN NEW(ntab, 40 * i) END;
  1148. at := ImpRva + ImpHSize; ai := 0; ni := 0;
  1149. lt := ImpRva + ImpSize; nt := lt + ImpSize - ImpHSize;
  1150. mod := modList;
  1151. WHILE mod # NIL DO
  1152. IF mod.dll THEN
  1153. Write4(lt); (* lookup table rva *)
  1154. Write4(0); (* time/data (always 0) *)
  1155. Write4(0); (* version (always 0) *)
  1156. Write4(nt + ni); (* name rva *)
  1157. ss := SHORT(mod.name$); Insert(ss, ni, -1);
  1158. Write4(at); (* addr table rva *)
  1159. exp := mod.exp;
  1160. WHILE exp # NIL DO
  1161. atab[ai] := nt + ni; (* hint/name rva *)
  1162. Insert(exp.name, ni, 0);
  1163. INC(lt, 4); INC(at, 4); INC(ai); exp := exp.next
  1164. END;
  1165. atab[ai] := 0; INC(lt, 4); INC(at, 4); INC(ai)
  1166. END;
  1167. mod := mod.next
  1168. END;
  1169. Write4(0); Write4(0); Write4(0); Write4(0); Write4(0);
  1170. i := 0;
  1171. WHILE i < ai DO Write4(atab[i]); INC(i) END; (* address table *)
  1172. i := 0;
  1173. WHILE i < ai DO Write4(atab[i]); INC(i) END; (* lookup table *)
  1174. i := 0;
  1175. WHILE i < ni DO WriteCh(ntab[i]); INC(i) END;
  1176. ASSERT(ai * 4 = ImpSize - ImpHSize);
  1177. INC(ImpSize, ai * 4 + ni);
  1178. ExpRva := ImpRva + (ImpSize + (ObjAlign - 1)) DIV ObjAlign * ObjAlign;
  1179. RelocRva := ExpRva;
  1180. END WriteImport;
  1181. PROCEDURE WriteExport (VAR name: ARRAY OF CHAR);
  1182. VAR i, ni: INTEGER; e: Export; ss: ARRAY 256 OF SHORTCHAR;
  1183. BEGIN
  1184. Write4(0); (* flags *)
  1185. Write4(timeStamp); (* time stamp *)
  1186. Write4(0); (* version *)
  1187. Write4(ExpRva + 40 + 10 * numExp); (* name rva *)
  1188. Write4(1); (* ordinal base *)
  1189. Write4(numExp); (* # entries *)
  1190. Write4(numExp); (* # name ptrs *)
  1191. Write4(ExpRva + 40); (* address table rva *)
  1192. Write4(ExpRva + 40 + 4 * numExp); (* name ptr table rva *)
  1193. Write4(ExpRva + 40 + 8 * numExp); (* ordinal table rva *)
  1194. ExpSize := 40 + 10 * numExp;
  1195. (* adress table *)
  1196. e := firstExp;
  1197. WHILE e # NIL DO Write4(e.adr); e := e.next END;
  1198. (* name ptr table *)
  1199. ni := 0; e := firstExp;
  1200. ss := SHORT(name$); Insert(ss, ni, -2);
  1201. WHILE e # NIL DO
  1202. Write4(ExpRva + ExpSize + ni); Insert(e.name, ni, -2); e := e.next
  1203. END;
  1204. (* ordinal table *)
  1205. i := 0;
  1206. WHILE i < numExp DO Write2(i); INC(i) END;
  1207. (* name table *)
  1208. i := 0;
  1209. WHILE i < ni DO WriteCh(ntab[i]); INC(i) END;
  1210. ExpSize := (ExpSize + ni + 15) DIV 16 * 16;
  1211. RelocRva := ExpRva + (ExpSize + (ObjAlign - 1)) DIV ObjAlign * ObjAlign;
  1212. END WriteExport;
  1213. PROCEDURE Sort (l, r: INTEGER);
  1214. VAR i, j, x, t: INTEGER;
  1215. BEGIN
  1216. i := l; j := r; x := fixups[(l + r) DIV 2];
  1217. REPEAT
  1218. WHILE fixups[i] < x DO INC(i) END;
  1219. WHILE fixups[j] > x DO DEC(j) END;
  1220. IF i <= j THEN t := fixups[i]; fixups[i] := fixups[j]; fixups[j] := t; INC(i); DEC(j) END
  1221. UNTIL i > j;
  1222. IF l < j THEN Sort(l, j) END;
  1223. IF i < r THEN Sort(i, r) END
  1224. END Sort;
  1225. PROCEDURE WriteReloc;
  1226. VAR i, j, h, a, p: INTEGER;
  1227. BEGIN
  1228. Sort(0, noffixup - 1); i := 0;
  1229. WHILE i < noffixup DO
  1230. p := fixups[i] DIV 4096 * 4096; j := i; a := p + 4096;
  1231. WHILE (j < noffixup) & (fixups[j] < a) DO INC(j) END;
  1232. Write4(p - ImageBase); (* page rva *)
  1233. h := 8 + 2 * (j - i);
  1234. Write4(h + h MOD 4); (* block size *)
  1235. INC(RelocSize, h);
  1236. WHILE i < j DO Write2(fixups[i] - p + 3 * 4096); INC(i) END; (* long fix *)
  1237. IF h MOD 4 # 0 THEN Write2(0); INC(RelocSize, 2) END
  1238. END;
  1239. Write4(0); Write4(0); INC(RelocSize, 8);
  1240. ImagesSize := RelocRva + (RelocSize + (ObjAlign - 1)) DIV ObjAlign * ObjAlign;
  1241. END WriteReloc;
  1242. PROCEDURE Align(VAR pos: INTEGER);
  1243. BEGIN
  1244. WHILE Ro.Pos() MOD FileAlign # 0 DO WriteCh(0X) END;
  1245. pos := Ro.Pos()
  1246. END Align;
  1247. PROCEDURE WriteOut (VAR name: Files.Name);
  1248. VAR res, codepos, conpos, rsrcpos, imppos, exppos, relpos, relend, end: INTEGER;
  1249. BEGIN
  1250. IF ~error THEN Align(codepos); WriteCode END;
  1251. IF ~error THEN Align(conpos); WriteConst END;
  1252. IF ~error THEN Align(rsrcpos); WriteResource END;
  1253. IF ~error THEN Align(imppos); WriteImport END;
  1254. IF ~error & isDll THEN Align(exppos); WriteExport(name) END;
  1255. IF ~error THEN Align(relpos); WriteReloc END;
  1256. relend := Ro.Pos() - 8; Align(end);
  1257. IF ~error THEN
  1258. Ro.SetPos(entryPos); Write4(CodeRva);
  1259. Ro.SetPos(isPos); Write4(ImagesSize);
  1260. IF isDll THEN
  1261. Ro.SetPos(hexpPos); Write4(ExpRva); Write4(ExpSize);
  1262. END;
  1263. Ro.SetPos(himpPos); Write4(ImpRva); Write4(ImpHSize);
  1264. Ro.SetPos(hrsrcPos); Write4(RsrcRva); Write4(RsrcSize);
  1265. Ro.SetPos(fixPos); Write4(RelocRva); Write4(relend - relpos);
  1266. Ro.SetPos(codePos); Write4(CodeRva); Write4(conpos - HeaderSize); Write4(HeaderSize);
  1267. Ro.SetPos(dataPos); Write4(DataRva); Write4((DataSize + (FileAlign-1)) DIV FileAlign * FileAlign);
  1268. Ro.SetPos(conPos); Write4(ConRva); Write4(rsrcpos - conpos); Write4(conpos);
  1269. Ro.SetPos(rsrcPos); Write4(RsrcRva); Write4(imppos - rsrcpos); Write4(rsrcpos);
  1270. IF isDll THEN
  1271. Ro.SetPos(impPos); Write4(ImpRva); Write4(exppos - imppos); Write4(imppos);
  1272. Ro.SetPos(expPos); Write4(ExpRva); Write4(relpos - exppos); Write4(exppos)
  1273. ELSE
  1274. Ro.SetPos(impPos); Write4(ImpRva); Write4(relpos - imppos); Write4(imppos);
  1275. END;
  1276. Ro.SetPos(relPos); Write4(RelocRva); Write4(end - relpos); Write4(relpos);
  1277. IF isStatic THEN
  1278. Ro.SetPos(termPos); WriteTermCode(modList, 0)
  1279. ELSIF isDll THEN
  1280. Ro.SetPos(termPos); WriteTermCode(main, 0)
  1281. END
  1282. END;
  1283. IF ~error THEN
  1284. Out.Register(name, "exe", Files.ask, res);
  1285. IF res # 0 THEN error := TRUE END
  1286. END
  1287. END WriteOut;
  1288. (* A. V. Shiryaev: Scanner *)
  1289. PROCEDURE (VAR S: Scanner) SetPos (x: INTEGER), NEW;
  1290. BEGIN
  1291. S.rider.i := x
  1292. END SetPos;
  1293. PROCEDURE (VAR S: Scanner) ConnectTo (IN src: ARRAY OF CHAR), NEW;
  1294. BEGIN
  1295. NEW(S.rider.s, LEN(src$) + 1);
  1296. S.rider.s^ := src$;
  1297. S.rider.i := 0;
  1298. S.start := 0;
  1299. S.type := TMEOT
  1300. END ConnectTo;
  1301. PROCEDURE (VAR R: ScanRider) ReadPrevChar (VAR ch: CHAR), NEW;
  1302. BEGIN
  1303. ch := R.s[R.i]
  1304. END ReadPrevChar;
  1305. PROCEDURE (VAR R: ScanRider) ReadChar (VAR ch: CHAR), NEW;
  1306. BEGIN
  1307. ch := R.s[R.i];
  1308. INC(R.i)
  1309. END ReadChar;
  1310. PROCEDURE (VAR R: ScanRider) Pos (): INTEGER, NEW;
  1311. BEGIN
  1312. RETURN R.i
  1313. END Pos;
  1314. PROCEDURE (VAR S: Scanner) Scan, NEW;
  1315. VAR j, res: INTEGER;
  1316. PROCEDURE IsLetter (c: CHAR): BOOLEAN;
  1317. BEGIN
  1318. RETURN ((c >= 'A') & (c <= 'Z')) OR ((c >= 'a') & (c <= 'z')) OR (c = '_')
  1319. END IsLetter;
  1320. PROCEDURE IsDigit (c: CHAR): BOOLEAN;
  1321. BEGIN
  1322. RETURN (c >= '0') & (c <= '9')
  1323. END IsDigit;
  1324. BEGIN
  1325. WHILE (S.rider.i < LEN(S.rider.s$)) & (S.rider.s[S.rider.i] = ' ') DO
  1326. INC(S.rider.i)
  1327. END;
  1328. IF S.rider.i < LEN(S.rider.s$) THEN
  1329. S.start := S.rider.i;
  1330. IF IsDigit(S.rider.s[S.rider.i]) THEN
  1331. j := 0;
  1332. WHILE (S.rider.i < LEN(S.rider.s$)) & IsDigit(S.rider.s[S.rider.i]) DO
  1333. S.string[j] := S.rider.s[S.rider.i];
  1334. INC(j);
  1335. INC(S.rider.i)
  1336. END;
  1337. S.string[j] := 0X;
  1338. Strings.StringToInt(S.string, S.int, res);
  1339. IF res # 0 THEN S.type := TMEOT
  1340. ELSE S.type := TMInt
  1341. END
  1342. ELSIF IsLetter(S.rider.s[S.rider.i]) THEN
  1343. S.type := TMString;
  1344. j := 0;
  1345. WHILE (S.rider.i < LEN(S.rider.s$)) & (IsLetter(S.rider.s[S.rider.i]) OR IsDigit(S.rider.s[S.rider.i])) DO
  1346. S.string[j] := S.rider.s[S.rider.i];
  1347. INC(j);
  1348. INC(S.rider.i)
  1349. END;
  1350. S.string[j] := 0X
  1351. ELSE
  1352. S.type := TMChar;
  1353. S.char := S.rider.s[S.rider.i];
  1354. INC(S.rider.i)
  1355. END
  1356. ELSE
  1357. S.type := TMEOT
  1358. END
  1359. END Scan;
  1360. PROCEDURE ScanRes (VAR S: Scanner; end: INTEGER; VAR list: Resource);
  1361. VAR res, tail: Resource; n: INTEGER;
  1362. BEGIN
  1363. tail := NIL;
  1364. WHILE (S.start < end) & (S.type = TMInt) DO
  1365. NEW(res); res.id := S.int; S.Scan;
  1366. IF (S.type = TMChar) & (S.char = "[") THEN
  1367. S.Scan;
  1368. IF S.type = TMInt THEN res.lid := S.int; S.Scan END;
  1369. IF (S.type = TMChar) & (S.char = "]") THEN S.Scan
  1370. ELSE WriteSString("missing ']'"); error := TRUE
  1371. END
  1372. END;
  1373. WHILE S.type = TMChar DO
  1374. IF S.char = "@" THEN n := 0
  1375. ELSIF S.char = "^" THEN n := 16
  1376. ELSIF S.char = "~" THEN n := 17
  1377. ELSIF S.char <= "?" THEN n := ORD(S.char) - ORD(" ")
  1378. END;
  1379. INCL(res.opts, n); S.Scan
  1380. END;
  1381. IF S.type = TMString THEN
  1382. res.name := S.string$; S.Scan;
  1383. IF (S.type = TMChar) & (S.char = ".") THEN S.Scan;
  1384. IF S.type = TMString THEN
  1385. IF (S.string = "tlb") OR (S.string = "TLB") THEN res.typ := -1 END;
  1386. Kernel.MakeFileName(res.name, S.string); S.Scan
  1387. END
  1388. END;
  1389. IF (S.type = TMChar) & (S.char = "(") THEN S.Scan;
  1390. ScanRes(S, end, res.local);
  1391. IF (S.type = TMChar) & (S.char = ")") THEN S.Scan
  1392. ELSE WriteSString("missing ')'"); error := TRUE
  1393. END
  1394. END;
  1395. IF tail = NIL THEN list := res ELSE tail.next := res END;
  1396. tail := res
  1397. ELSE
  1398. WriteSString("wrong resource name"); error := TRUE
  1399. END
  1400. END;
  1401. END ScanRes;
  1402. PROCEDURE LinkIt (IN txt: ARRAY OF CHAR);
  1403. VAR S: Scanner; name: Files.Name; mod: Module; end: INTEGER;
  1404. BEGIN
  1405. comLine := FALSE;
  1406. modList := NIL; kernel := NIL; main := NIL;
  1407. last := NIL; impg := NIL; impd := NIL; resList := NIL;
  1408. firstExp := NIL; lastExp := NIL;
  1409. NEW(fixups, FixLen);
  1410. (*
  1411. Dialog.ShowStatus("linking");
  1412. *)
  1413. Console.WriteStr("linking"); Console.WriteLn;
  1414. (*
  1415. timeStamp := TimeStamp();
  1416. *)
  1417. timeStamp := 0;
  1418. error := FALSE; modList := NIL; resList := NIL;
  1419. (*
  1420. IF DevCommanders.par = NIL THEN RETURN END;
  1421. S.ConnectTo(DevCommanders.par.text);
  1422. S.SetPos(DevCommanders.par.beg);
  1423. end := DevCommanders.par.end;
  1424. DevCommanders.par := NIL;
  1425. W.ConnectTo(Log.buf);
  1426. *)
  1427. S.ConnectTo(txt);
  1428. S.SetPos(0);
  1429. end := LEN(txt$);
  1430. S.Scan;
  1431. IF S.type = TMString THEN
  1432. IF S.string = "dos" THEN comLine := TRUE; S.Scan END;
  1433. name := S.string$; S.Scan;
  1434. IF (S.type = TMChar) & (S.char = ".") THEN S.Scan;
  1435. IF S.type = TMString THEN
  1436. Kernel.MakeFileName(name, S.string); S.Scan
  1437. END
  1438. ELSE Kernel.MakeFileName(name, "EXE");
  1439. END;
  1440. IF (S.type = TMChar) & (S.char = ":") THEN S.Scan;
  1441. IF (S.type = TMChar) & (S.char = "=") THEN S.Scan;
  1442. WHILE (S.start < end) & (S.type = TMString) DO
  1443. NEW(mod); mod.name := S.string$;
  1444. mod.next := modList; modList := mod;
  1445. S.Scan;
  1446. WHILE (S.start < end) & (S.type = TMChar) &
  1447. ((S.char = "*") OR (S.char = "+") OR (S.char = "$") OR (S.char = "#")) DO
  1448. IF S.char = "*" THEN mod.dll := TRUE
  1449. ELSIF S.char = "+" THEN kernel := mod
  1450. ELSIF S.char = "$" THEN main := mod
  1451. ELSE mod.intf := TRUE;
  1452. IF ~isDll THEN
  1453. WriteSString("Exports from Exe not possible. Use LinkDll or LinkDynDll.");
  1454. WriteLn; FlushW; error := TRUE
  1455. END
  1456. END;
  1457. S.Scan
  1458. END
  1459. END;
  1460. ScanRes(S, end, resList);
  1461. ReadHeaders;
  1462. PrepResources;
  1463. IF ~error THEN WriteHeader(name) END;
  1464. IF ~error THEN WriteOut(name) END;
  1465. IF ~error THEN
  1466. WriteString(name); WriteString(" written ");
  1467. WriteInt(Out.Length()); WriteString(" "); WriteInt(CodeSize)
  1468. END
  1469. ELSE WriteString(" := missing")
  1470. END
  1471. ELSE WriteString(" := missing")
  1472. END;
  1473. WriteLn; FlushW
  1474. END;
  1475. (*
  1476. IF error THEN Dialog.ShowStatus("failed") ELSE Dialog.ShowStatus("ok") END;
  1477. W.ConnectTo(NIL); S.ConnectTo(NIL);
  1478. *)
  1479. IF error THEN Console.WriteStr("failed") ELSE Console.WriteStr("ok") END; Console.WriteLn;
  1480. S.ConnectTo("");
  1481. modList := NIL; kernel := NIL; main := NIL; firstExp := NIL; lastExp := NIL;
  1482. last := NIL; impg := NIL; impd := NIL; resList := NIL; code := NIL; atab := NIL; ntab := NIL;
  1483. fixups := NIL
  1484. END LinkIt;
  1485. PROCEDURE Link* (IN txt: ARRAY OF CHAR);
  1486. BEGIN
  1487. isDll := FALSE; isStatic := FALSE;
  1488. LinkIt(txt)
  1489. END Link;
  1490. PROCEDURE LinkExe* (IN txt: ARRAY OF CHAR);
  1491. BEGIN
  1492. isDll := FALSE; isStatic := TRUE;
  1493. LinkIt(txt)
  1494. END LinkExe;
  1495. PROCEDURE LinkDll* (IN txt: ARRAY OF CHAR);
  1496. BEGIN
  1497. isDll := TRUE; isStatic := TRUE;
  1498. LinkIt(txt)
  1499. END LinkDll;
  1500. PROCEDURE LinkDynDll* (IN txt: ARRAY OF CHAR);
  1501. BEGIN
  1502. isDll := TRUE; isStatic := FALSE;
  1503. LinkIt(txt)
  1504. END LinkDynDll;
  1505. (*
  1506. PROCEDURE Show*;
  1507. VAR S: TextMappers.Scanner; name: Name; mod: Module; t: TextModels.Model;
  1508. BEGIN
  1509. t := TextViews.FocusText(); IF t = NIL THEN RETURN END;
  1510. W.ConnectTo(Log.buf); S.ConnectTo(t); S.Scan;
  1511. IF S.type = TextMappers.string THEN
  1512. mod := modList;
  1513. WHILE (mod # NIL) & (mod.name # S.string) DO mod := mod.next END;
  1514. IF mod # NIL THEN
  1515. W.WriteString(S.string);
  1516. W.WriteString(" ca = ");
  1517. W.WriteIntForm(CodeBase + mod.ca, TextMappers.hexadecimal, 8, "0", TRUE);
  1518. W.WriteLn; Log.text.Append(Log.buf)
  1519. END
  1520. END;
  1521. W.ConnectTo(NIL); S.ConnectTo(NIL)
  1522. END Show;
  1523. *)
  1524. BEGIN
  1525. newRec := "NewRec"; newArr := "NewArr"
  1526. END Dev0Linker.
  1527. (!)DevLinker.Link Usekrnl.exe := TestKernel$+ Usekrnl ~ (!)"DevDecExe.Decode('', 'Usekrnl.exe')"
  1528. (!)DevLinker.LinkDynDll MYDLL.dll := TestKernel+ MYDLL$# ~ (!)"DevDecExe.Decode('', 'MYDLL.dll')"
  1529. (!)DevLinker.LinkExe Usekrnl.exe := TestKernel+ Usekrnl ~ (!)"DevDecExe.Decode('', 'Usekrnl.exe')"
  1530. (!)DevLinker.LinkDll MYDLL.dll := TestKernel+ MYDLL# ~ (!)"DevDecExe.Decode('', 'MYDLL.dll')"
  1531. MODULE TestKernel;
  1532. IMPORT KERNEL32;
  1533. PROCEDURE Beep*;
  1534. BEGIN
  1535. KERNEL32.Beep(500, 200)
  1536. END Beep;
  1537. BEGIN
  1538. CLOSE
  1539. KERNEL32.ExitProcess(0)
  1540. END TestKernel.
  1541. MODULE Usekrnl;
  1542. (* empty windows application using BlackBox Kernel *)
  1543. (* Ominc (!) *)
  1544. IMPORT KERNEL32, USER32, GDI32, S := SYSTEM, Kernel := TestKernel;
  1545. VAR Instance, MainWnd: USER32.Handle;
  1546. PROCEDURE WndHandler (wnd, message, wParam, lParam: INTEGER): INTEGER;
  1547. VAR res: INTEGER; ps: USER32.PaintStruct; dc: GDI32.Handle;
  1548. BEGIN
  1549. IF message = USER32.WMDestroy THEN
  1550. USER32.PostQuitMessage(0)
  1551. ELSIF message = USER32.WMPaint THEN
  1552. dc := USER32.BeginPaint(wnd, ps);
  1553. res := GDI32.TextOutA(dc, 50, 50, "Hello World", 11);
  1554. res := USER32.EndPaint(wnd, ps)
  1555. ELSIF message = USER32.WMChar THEN
  1556. Kernel.Beep
  1557. ELSE
  1558. RETURN USER32.DefWindowProcA(wnd, message, wParam, lParam)
  1559. END;
  1560. RETURN 0
  1561. END WndHandler;
  1562. PROCEDURE OpenWindow;
  1563. VAR class: USER32.WndClass; res: INTEGER;
  1564. BEGIN
  1565. class.cursor := USER32.LoadCursorA(0, USER32.MakeIntRsrc(USER32.IDCArrow));
  1566. class.icon := USER32.LoadIconA(Instance, USER32.MakeIntRsrc(1));
  1567. class.menuName := NIL;
  1568. class.className := "Simple";
  1569. class.backgnd := GDI32.GetStockObject(GDI32.WhiteBrush);
  1570. class.style := {0, 1, 5, 7};
  1571. class.instance := Instance;
  1572. class.wndProc := WndHandler;
  1573. class.clsExtra := 0;
  1574. class.wndExtra := 0;
  1575. USER32.RegisterClassA(class);
  1576. MainWnd := USER32.CreateWindowExA({}, "Simple", "Empty Windows Application",
  1577. {16..19, 22, 23, 25},
  1578. USER32.CWUseDefault, USER32.CWUseDefault,
  1579. USER32.CWUseDefault, USER32.CWUseDefault,
  1580. 0, 0, Instance, 0);
  1581. res := USER32.ShowWindow(MainWnd, 10);
  1582. res := USER32.UpdateWindow(MainWnd);
  1583. END OpenWindow;
  1584. PROCEDURE MainLoop;
  1585. VAR msg: USER32.Message; res: INTEGER;
  1586. BEGIN
  1587. WHILE USER32.GetMessageA(msg, 0, 0, 0) # 0 DO
  1588. res := USER32.TranslateMessage(msg);
  1589. res := USER32.DispatchMessageA(msg);
  1590. END;
  1591. (*
  1592. KERNEL32.ExitProcess(msg.wParam)
  1593. *)
  1594. END MainLoop;
  1595. BEGIN
  1596. Instance := KERNEL32.GetModuleHandleA(NIL);
  1597. OpenWindow;
  1598. MainLoop
  1599. CLOSE
  1600. Kernel.Beep
  1601. END Usekrnl.
  1602. MODULE MYDLL;
  1603. (* sample module to be linked into a dll *)
  1604. (* Ominc (!) *)
  1605. IMPORT SYSTEM, KERNEL32;
  1606. VAR expVar*: INTEGER;
  1607. PROCEDURE GCD* (a, b: INTEGER): INTEGER;
  1608. BEGIN
  1609. WHILE a # b DO
  1610. IF a < b THEN b := b - a ELSE a := a - b END
  1611. END;
  1612. expVar := a;
  1613. RETURN a
  1614. END GCD;
  1615. PROCEDURE Beep*;
  1616. BEGIN
  1617. KERNEL32.Beep(500, 200)
  1618. END Beep;
  1619. CLOSE
  1620. Beep
  1621. END MYDLL.
  1622. Resource = Id [ "[" Language "]" ] Options name [ "." ext ] [ "(" { Resource } ")" ]
  1623. Id = number
  1624. Language = number
  1625. Options = { "@" | "!" .. "?" | "^" | "~" }
  1626. names
  1627. MENU
  1628. 1 MENU (0 File (11 New 12 Open 13 Save 0 "" 14 Exit) 0 Edit (21 Cut 22 Copy 23 Paste))
  1629. = grayed
  1630. - inctive
  1631. # bitmap
  1632. * checked
  1633. ! menuBarBreak
  1634. / menuBreak
  1635. ? ownerDraw
  1636. ACCELERATOR
  1637. 1 ACCELERATOR (11 ^N 12 ^O 13 ^S 21 ^X 22 ^C 23 ^V)
  1638. * shift
  1639. ^ ctrl
  1640. @ alt
  1641. - noInvert
  1642. filename.ico
  1643. filename.cur
  1644. filname.bmp
  1645. filename.res
  1646. filename.tlb